2

i am in a bit tricky situation. I fetch some price values from a sqlite db and store it in a react state.

the response looks like: [{"price":50},{"price":"49,95"}]

i need to store these values as TEXT insted of INTEGER, because i have a lot of differrent decimal places. also using float in sqlite will not give me exact values, see the problem in this example: https://dba.stackexchange.com/questions/15729/storing-prices-in-sqlite-what-data-type-to-use

So to my main problem: how can i extract and convert the values from the json array to numbers, and sum it up?

4
  • 1
    What does "i have a lot of differrent decimal places" mean? There are different approaches to avoid rounding errors. Convert the strings and numbers to integers: 50 -> 5000, "49,95" -> 4995. Use a library for fixed-point arithmetic. Use a library for infinite precision. Do the calculation based on strings. Commented Feb 23, 2022 at 12:19
  • 2
    Wouldn't the preferred option be to make sure the data you're receiving from the database is sanitised and correct, and that all the values were text, and not a mix of numbers/text? Commented Feb 23, 2022 at 12:20
  • @jabaa this means, some values are 49.95, some are 65.7862437482 Commented Feb 23, 2022 at 12:30
  • In that case, the first approach won't work. But the other 3 still work. I guess, under the hood, all 3 approaches do something similar. They store each digit as a separate element in a container (string, array). Commented Feb 23, 2022 at 12:32

1 Answer 1

1

If you don't want to use a library, you could convert all numbers to strings and write your own sum function for strings. This algorithm supports arbitrary long strings containing numbers and returns exact results without rounding errors.

function add(l, r, sep) {
  if (!sep) sep = '.';
  const [ll, lr] = l.split(/[,.]/).map(el => el.split('').map(Number));
  const [rl, rr] = r.split(/[,.]/).map(el => el.split('').map(Number));
  let carry = 0;
  const result = [[], []];
  for (let i = Math.max(lr?.length ?? 0, rr?.length ?? 0); i > 0; --i) {
    result[1][i - 1] = (lr?.[i - 1] ?? 0) + (rr?.[i - 1] ?? 0) + carry;
    carry = Math.floor(result[1][i - 1] / 10);
    result[1][i - 1] %= 10;
  }
  
  for (let il = ll.length, ir = rl.length, iResult = Math.max(ll.length, rl.length); iResult > 0; --il, --ir, --iResult) {
    result[0][iResult - 1] = (ll[il - 1] ?? 0) + (rl[ir - 1] ?? 0) + carry;
    carry = Math.floor(result[0][iResult - 1] / 10);
    result[0][iResult - 1] %= 10;
  }
  if (carry) result[0] = [carry, ...result[0]];
  return result[0].join('') + sep + result[1].join('');
}

function sum(arr, sep) {
  return arr.map(el => String(el.price)).reduce((acc, el) => add(acc, el, sep));
}

console.log(sum([{ "price": "0.9" }, { "price": "1.2" }], ','));
console.log(sum([{ "price": "100000000" }, { "price": "0.0000002" }]));
console.log(sum([{ "price": 123.123 }, { "price": "1234.5678" }, { "price": "9876,54321" }, { "price": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111.111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"}]));

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! this is exactly what im looking for!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.