1

I have a array like this in below, What I'm trying is seperating objects to new array by grouping two values.

Array:

[
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

Result should be like this;

Output

[
 [
  {
   "year": "202003",
   "cost": 11194.55,
   "type": "A"
  }
 ],
 [ 
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  }
 ],
 [
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  }
 ],
 [
  {
    "year": "202003",
    "cost": 1494.24,     // sum of the COST value when year and type same.
    "type": "D"
  },
  {
     "year": "202004",
     "cost": 4674.59,
     "type": "D"
  }
 ]
];

What I've tried

<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>
let aggregatedObject = Enumerable.From(data)
            .GroupBy("$.type", "$.year",
                function (key, g) {
                    return {
                        label: key,
                        value: g.Sum("$.cost"),
                    }
                })
            .ToArray();

How can I group this data like this? Is there any library or a function to do this? I couldn't find yet. Any help will be highly appreciated!

1
  • Use reduce method and find Commented Jun 30, 2020 at 20:16

4 Answers 4

1

Looking at your initial array and the output you wanted to get, below are the examples that result in exactly the same structure as per your question - an array of arrays of objects


One way with find & for of loop:

let arr = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

let sortedArray = []
for (let [index, el] of arr.entries()) {
  if(sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year !== el.year))) {
    sortedArray.find(elInner => elInner[0].type === el.type).push(arr[index])
  }else if (sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year == el.year))) {
    sortedArray.find(elInner => (elInner[0].type === el.type && elInner[0].year == el.year))[0].cost += arr[index].cost
  }else {
    sortedArray.push([el])
  }
}
console.log(sortedArray)


and another "cleaner" way with reduce & map

let arr = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
]

let sortedArray = arr.reduce((acc, obj) => {
  const key = obj.type, year = obj.year
  !!acc[key] 
  ? (!!acc[key][year] ? acc[key][year].cost += obj.cost : acc[key][year] = obj) 
  : (acc[key] = [], acc[key][year] = obj)
    return acc
}, [])

sortedArray = Object.values(sortedArray).map((val) => Object.values(val))

console.log(sortedArray)

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

Comments

1

You can use Array.reduce in order to accumulate the cost.

const data = [
  {
    year: '202003',
    cost: 11194.55,
    type: 'A',
  },
  {
    year: '202003',
    cost: 60.2,
    type: 'B',
  },
  {
    year: '202003',
    cost: 747.12,
    type: 'C',
  },
  {
    year: '202003',
    cost: 747.12,
    type: 'D',
  },
  {
    year: '202004',
    cost: 747.12,
    type: 'D',
  },
  {
    year: '202003',
    cost: 4674.59,
    type: 'D',
  },
];

const final = data.reduce((result, current) => {
  const key = `${current.year}-${current.type}`;
  result[key] = result[key] || {...current, cost: 0};
  result[key].cost += current.cost;
  return result;
}, {});

console.log(Object.values(final).map(item => ([item])));

3 Comments

Thanks for you contribution but I'm also trying to add this types different arrays. This shouldn't be like a single array.
I'm not sure what you mean
In my output example all types are added like arrays, not like object in a single array
1

You can try to use array.reduce instead of linq.js, every callback execution accumulates the data if there's matching year and type or adds a copy of an object to an array which is returned from the function:

let data = [
 {
    "year": "202003",
    "cost": 11194.55,
    "type": "A"
  },
  {
    "year": "202003",
    "cost": 60.2,
    "type": "B"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "C"
  },
  {
    "year": "202003",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202004",
    "cost": 747.12,
    "type": "D"
  },
  {
    "year": "202003",
    "cost": 4674.59,
    "type": "D"
  }
];

let aggregatedObject = data.reduce((acc,cur) => {
   let prev = acc.find(x => x.year === cur.year && x.type === cur.type);
   if(!prev){
       acc.push([{...cur}]);
   } else {
       prev.cost += cur.cost;
   }
   return acc;
}, []);

console.log(aggregatedObject);

1 Comment

Thanks for your contribution. I'm also trying to add this objects to different arrays not in same array of objects. [ [ ], [ ] ] like this. When types are different it should be an array.
1

You could take a joined key with linq as forth parameter and a combined object for getting a summed value.

var data = [{ year: "202003", cost: 11194.55, type: "A" }, { year: "202003", cost: 60.2, type: "B" }, { year: "202003", cost: 747.12, type: "C" }, { year: "202003", cost: 747.12, type: "D" }, { year: "202004", cost: 747.12, type: "D" }, { year: "202003", cost: 4674.59, type: "D" }],
    result = Enumerable
        .From(data)
        .GroupBy(
            null,
            null,
            "{ year: $.year, cost: $$.Sum('$.cost'), type: $.type }",
            "$.year + '|' + $.type"
        )
        .ToArray();

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>

1 Comment

thanks for your response, it need some improvement. Such as types should be in different array.

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.