skip to Main Content

I have two data sets from the same API call on two different dates and I want to calculate variance between values of those two arrays of objects received using javascript. The following are two data sets.

const arrayOne = [
        {
            id: 1,
            values: {
                sales: {
                    rawValue: 3,
                    value: '3.0',
                },
            },
        },
        {
            id: 2,
            values: {
                sales: {
                    rawValue: 1,
                    value: '1.0',
                },
            },
        },
    ];

const arrayTwo = [
        {
            id: 1,
            values: {
                sales: {
                    rawValue: 1.1,
                    value: '1.1',
                },
            },
        },
        {
            id: 2,
            values: {
                sales: {
                    rawValue: 2,
                    value: '2.0',
                },
            },
        },
    ];

I am trying to create a new array with the following objects with calculated variance init:

const newArray = [
        {
            id: 1,
            values: {
                salesVar: {
                    rawValue: calculatedVariance,
                    value: 'calculatedVariance',
                },
            },
        },
        {
            id: 2,
            values: {
                salesVar: {
                    rawValue: calculatedVariance,
                    value: 'calculatedVariance',
                },
            },
        },
    ];

Is there any possible solution for this using javascript?

2

Answers


  1. Calculating variance is straightforward – the difficult part is navigating around the data structures.

    const arrayOne = [{"id":1,"values":{"sales":{"rawValue":3,"value":"3.0"}}},{"id":2,"values":{"sales":{"rawValue":1,"value":"1.0"}}}]
    const arrayTwo = [{"id":1,"values":{"sales":{"rawValue":1.1,"value":"1.1"}}},{"id":2,"values":{"sales":{"rawValue":2,"value":"2.0"}}}]
    
    const input = [arrayOne, arrayTwo]
    
    const sums = input.flat()
      .reduce((a,{id, values:{sales:{rawValue}}}) =>
        (a[id]??=0, a[id]+=rawValue, a), {})
    
    const counts = input.flat()
      .reduce((a,{id}) => (a[id]??=0, a[id]+=1, a), {})
    
    const means = Object.fromEntries(
      Object.entries(sums).map(([id, sum]) => ([id, sum/counts[id]])))
    
    const sumsValueMinusMeanSquared = input.flat()
      .reduce((a,{id, values:{sales:{rawValue}}}) =>
        (a[id]??=0, a[id]+=Math.pow(rawValue-means[id], 2), a), {})
    
    const sumsValueMinusMeanSquaredDivN = 
      Object.fromEntries(Object.entries(
        sumsValueMinusMeanSquared).map(([id, x])=>[id, x/counts[id]]))
    
    console.log(sums)
    console.log(counts)
    console.log(means)
    console.log(sumsValueMinusMeanSquared)
    console.log(sumsValueMinusMeanSquaredDivN)
    
    const output = Object.entries(sumsValueMinusMeanSquaredDivN)
      .map(([id, variance]) =>
        ({id, values: {salesVar: {rawValue: variance, value: String(variance)}}}))
    
    console.log(output)
    Login or Signup to reply.
  2. Assuming the two arrays contain objects of the same shape and in the same order, then it is very simple to use Lodash’s mergeWith to combine the two. The function accepts a customiser argument which can do the calculation:

    const numberFormatter = new Intl.NumberFormat("en-US", { 
      type: "decimal",
      minimumFractionDigits: 1,
      maximumFractionDigits: 20,
    });
    
    const calculateVariance = (firstValue, secondValue) =>
      ((firstValue - secondValue) / firstValue) * 100
    
    const calculateVarianceAsString = (firstValue, secondValue) =>
      numberFormatter.format(
        calculateVariance(Number(firstValue), Number(secondValue))
      );
      
    function combineWithVariance(arr1, arr2) {
      return _.mergeWith(arr1, arr2, (a, b, key) => {
        if (key === "rawValue")
          return calculateVariance(a, b);
        if (key === "value")
          return calculateVarianceAsString(a, b);
      });
    }
    
    const arrayOne = [{ id: 1, values: { sales: { rawValue: 3  , value: '3.0', },},}, { id: 2, values: { sales: { rawValue: 1, value: '1.0', },},},]; 
    const arrayTwo = [{ id: 1, values: { sales: { rawValue: 1.1, value: '1.1', },},}, { id: 2, values: { sales: { rawValue: 2, value: '2.0', },},},];
    
    console.log(combineWithVariance(arrayOne, arrayTwo));
    .as-console-wrapper { max-height: 100% !important; }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

    In this case, the customiser only handles rawValue and value properties. For everything else, the customiser just returns undefined which allows Lodash to handle the recursive merging by automatically.

    For the cases where the result is handled by the customiser, calculateVariance() handles the calculation, while calculateVarianceAsString() formats the result using Intl.NumberFormat#format() to show a ".0" at the end of the number, even if it does not have fractional part. But Show as much of the fraction as possible otherwise.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search