Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split array with objects to multiple arrays based on unique combination

Tags:

javascript

I have a dataset like this:

var dataset = [
{time: "t1", locA: "a1", locB: "b1", value: v1},
{time: "t1", locA: "a1", locB: "b2", value: v2},
{time: "t1", locA: "a2", locB: "b1", value: v3},
{time: "t1", locA: "a2", locB: "b2", value: v4},
{time: "t2", locA: "a1", locB: "b1", value: v5},
{time: "t2", locA: "a1", locB: "b2", value: v6},
{time: "t2", locA: "a2", locB: "b1", value: v7},
{time: "t2", locA: "a2", locB: "b2", value: v8},
....
];

I want a result like this:

var a1b1 = [ 
{loc: "a1b1", time: "t1", value: "v1"},
{loc: "a1b1", time: "t2", value: "v5"},
....
];
var a1b2 = [ 
{loc: "a1b2", time: "t1", value: "v2"},
{loc: "a1b2", time: "t2", value: "v6"},
....
];
var a2b1 = [ 
{loc: "a2b1", time: "t1", value: "v3"},
{loc: "a2b1", time: "t2", value: "v7"},
....
];
var a2b2 = [ 
{loc: "a2b2", time: "t1", value: "v4"},
{loc: "a2b2", time: "t2", value: "v8"},
....
];

It's important that the t values are in the correct order while it represents time. I cannot use libraries, just vintage JavaScript. I found some older SO posts with splitting an array of objects but they describe just simple splitting or using libraries.

Is it possible with forEach like

dataset.forEach(function()...

Any help is appreciated..

like image 635
3TW3 Avatar asked Sep 04 '17 19:09

3TW3


2 Answers

Another short Array.prototype.reduce() approach:

var dataset = [
  {time: "t1", locA: "a1", locB: "b1", value: "v1"}, {time: "t1", locA: "a1", locB: "b2", value: "v2"}, {time: "t1", locA: "a2", locB: "b1", value: "v3"}, 
  {time: "t1", locA: "a2", locB: "b2", value: "v4"}, {time: "t2", locA: "a1", locB: "b1", value: "v5"}, {time: "t2", locA: "a1", locB: "b2", value: "v6"}, {time: "t2", locA: "a2", locB: "b1", value: "v7"}, {time: "t2", locA: "a2", locB: "b2", value: "v8"}
];

var result = dataset.reduce(function(r, o){
    var k = o.locA + o.locB;   // unique `loc` key
    if (r[k] || (r[k]=[])) r[k].push({loc:k, time: o.time, value: o.value});
    return r;
}, {});

console.log(result);
like image 158
RomanPerekhrest Avatar answered Nov 15 '22 02:11

RomanPerekhrest


You can use reduce to group the objects:

function group(arr) {
  return arr.reduce(function(res, obj) {                         // for each object obj in the array arr
    var key = obj.locA + obj.locB;                               // let key be the concatination of locA and locB
    var newObj = {loc: key, time: obj.time, value: obj.value};   // create a new object based on the object obj
    if(res[key])                                                 // if res has a sub-array for the current key then...
      res[key].push(newObj);                                     // ... push newObj into that sub-array
    else                                                         // otherwise...
      res[key] = [ newObj ];                                     // ... create a new sub-array for this key that initially contain newObj
    return res;
  }, {});
}

var result = group([
  {time: "t1", locA: "a1", locB: "b1", value: "v1"},
  {time: "t1", locA: "a1", locB: "b2", value: "v2"},
  {time: "t1", locA: "a2", locB: "b1", value: "v3"},
  {time: "t1", locA: "a2", locB: "b2", value: "v4"},
  {time: "t2", locA: "a1", locB: "b1", value: "v5"},
  {time: "t2", locA: "a1", locB: "b2", value: "v6"},
  {time: "t2", locA: "a2", locB: "b1", value: "v7"},
  {time: "t2", locA: "a2", locB: "b2", value: "v8"}
]);

console.log(result);

Note: Instead of assigning the values to separate variables a1b1, a1b2, ... (which won't be very flexible and dynamic), my answer groups the results into one big object that contain the arrays (results) under their equivalent keys. So result is like this:

result = {
    "a1b1": [ ... ],
    "a1b2": [ ... ],
    ...
}
like image 2
ibrahim mahrir Avatar answered Nov 15 '22 03:11

ibrahim mahrir