5

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..

5 Answers 5

7

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);

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

Comments

2

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": [ ... ],
    ...
}

6 Comments

Your answer returns an object, the OP wanted an array
@Minasploit OP doesn't want "an" array, OP wants multiple arrays (each referenced by its own variable). Grouping those arrays under one big object and referencing them using keys is the cleanest solution to OP's problem. The other solution would require adding them to window object which kind of messy as it will create those variables in the global scope which is not ideal
I'm not saying yours is a bad idea but in the OP's question, he described what kind of data he wants and it seems to me like the array a1b1 is an array
@Minasploit "it seems to me like the array a1b1 is an array", what do you mean? a1b1 is an array, OP wants it to be an array. My answer does exactly what OP wants except for storing each array in its own variable which, as I told you before, is very messy. All the other answers (including the accepted one) produce the same output as mine
I hadn't seen the answers given by the other people. I apologize for wasting your time. And you should know that I did use your solution and worked out perfectly well for me. Thanks for your input!!!
|
1

Something like this?

var dataset = [
{time: "t1", locA: "a1", locB: "b1", value: 0},
{time: "t1", locA: "a1", locB: "b2", value: 1},
{time: "t1", locA: "a2", locB: "b1", value: 2},
{time: "t1", locA: "a2", locB: "b2", value: 3},
{time: "t2", locA: "a1", locB: "b1", value: 4},
{time: "t2", locA: "a1", locB: "b2", value: 5},
{time: "t2", locA: "a2", locB: "b1", value: 6},
{time: "t2", locA: "a2", locB: "b2", value: 7}
];

var result = {};

dataset
  .sort((a, b) => { 
    return Number(a.time.replace(/\D/g, '')) > Number(b.time.replace(/\D/g, ''));
  })
  .forEach(d => {
    var key = d.locA + d.locB;

    if (!result[key]) {
      result[key] = [];
    }

    result[key].push({
      loc: key,
      time: d.time,
      value: d.value
    });
  });

console.log(result);

If you really want to create vars like var a1b1 instead of an object as result, replace result[key] with window[key] inside the loop.

Comments

0

using lodash _.keyBy you can split it on the bases of key. link to the function https://lodash.com/docs/4.17.4#keyBy .

Comments

0

I assumed the values are ordered by time in the original data set. Then it is just a matter of collating the data.

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'}
];

// The key for an item is locA joined with locB.
function getItemKey(item) {
  return item.locA + item.locB;
}

// Method for transforming an item into the desired data structure.
function transformItem(item) {
  return {
    loc: getItemKey(item),
    time: item.time,
    value: item.value
  };
}

// Method for collating the dataset so items with a matching locA / locB are grouped together.
function collateLocationData(dataSet) {
  const
    resultMap = new Map();
    
  // Iterate over the data set.
  dataSet.forEach(item => {
    const 
      // Get the key for current item.
      itemKey = getItemKey(item);
    // Check if the key exists in the map...
    if (resultMap.has(itemKey)) {
      // ... and when it does add the transformed item to the key's value.
      resultMap.get(itemKey).push(transformItem(item));
    } else {
      // ... and when it doesn't add the key to the map with the transformed item.
      resultMap.set(itemKey, [transformItem(item)]);
    }
  });
  
  // Return the map.
  return resultMap;
}


const 
  collatedData = collateLocationData(dataset);


/* === LOGGING THE MAP TO THE CONSOLE === */
function itemToString(items) { 
  return items.reduce((html, item) => {
    if (html !== '' ) {
      html += ' || ';
    }
    return html + `loc: ${item.loc} / time: ${item.time} / value: ${item.value}`;
  }, '');
}

collatedData.forEach((values, key) => {
  console.log(`${key} = ${itemToString(values)}`);
});

Comments

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.