基于唯一组合将具有对象的数组拆分为多个数组

时间:2022-10-23 12:18:26

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.

重要的是t值表示正确的顺序,而它代表时间。我不能使用库,只有老式JavaScript。我发现了一些较旧的SO帖子,它们拆分了一个对象数组,但它们描述的只是简单的拆分或使用库。

Is it possible with forEach like

是否可以与forEach一样

dataset.forEach(function()...

Any help is appreciated..

任何帮助表示赞赏..

5 个解决方案

#1


2  

Another short Array.prototype.reduce() approach:

另一个简短的Array.prototype.reduce()方法:

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

#2


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.

如果你真的想要创建变量如var a1b1而不是对象作为结果,请在循环内用window [key]替换result [key]。

#3


1  

You can use reduce to group the objects:

您可以使用reduce对对象进行分组:

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:

注意:我没有将值分配给单独的变量a1b1,a1b2,...(这将不是非常灵活和动态),我的答案将结果分组为一个大对象,其中包含其等效键下的数组(结果)。所以结果是这样的:

result = {
    "a1b1": [ ... ],
    "a1b2": [ ... ],
    ...
}

#4


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 .

使用lodash _.keyBy你可以在key的基础上拆分它。链接到功能https://lodash.com/docs/4.17.4#keyBy。

#5


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

#1


2  

Another short Array.prototype.reduce() approach:

另一个简短的Array.prototype.reduce()方法:

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

#2


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.

如果你真的想要创建变量如var a1b1而不是对象作为结果,请在循环内用window [key]替换result [key]。

#3


1  

You can use reduce to group the objects:

您可以使用reduce对对象进行分组:

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:

注意:我没有将值分配给单独的变量a1b1,a1b2,...(这将不是非常灵活和动态),我的答案将结果分组为一个大对象,其中包含其等效键下的数组(结果)。所以结果是这样的:

result = {
    "a1b1": [ ... ],
    "a1b2": [ ... ],
    ...
}

#4


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 .

使用lodash _.keyBy你可以在key的基础上拆分它。链接到功能https://lodash.com/docs/4.17.4#keyBy。

#5


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