在对象数组中合并带有“相同键”的对象

时间:2020-09-24 17:10:25

标签: javascript

我有一个这样的对象数组:

const dataset = 
  [ { date: '2018-01', color: 'red',  value1: null, value2: null, value3: 2,    value4: 6    } 
  , { date: '2018-01', color: 'red',  value1: 0,    value2: 4,    value3: null, value4: null } 
  , { date: '2018-02', color: 'red',  value1: null, value2: null, value3: 2,    value4: 10   } 
  , { date: '2018-02', color: 'red',  value1: -9,   value2: 0,    value3: null, value4: null } 
  , { date: '2019-01', color: 'blue', value1: null, value2: null, value3: 10,   value4: 3    } 
  , { date: '2019-01', color: 'blue', value1: -2,   value2: 8,    value3: null, value4: null } 
  , { date: '2019-02', color: 'blue', value1: null, value2: null, value3: 20,   value4: 2    } 
  , { date: '2019-02', color: 'blue', value1: 9,    value2: 7,    value3: null, value4: null } 
  , ...
  ]

我想要

const result = 
  [ { date: '2018-01', color: 'red',  value1: 0,  value2: 4, value3: 2,  value4: 6  } 
  , { date: '2018-02', color: 'red',  value1: -9, value2: 0, value3: 2,  value4: 10 } 
  , { date: '2019-01', color: 'blue', value1: -2, value2: 8, value3: 10, value4: 3  } 
  , { date: '2019-02', color: 'blue', value1: 9,  value2: 7, value3: 20, value4: 2  } 
  , ...
  ] 

result包含与dataset相同的信息。
具有相同datecolor的记录将合并到gheter中,并且将空值替换为可用数据。

我该怎么做?我不知道

4 个答案:

答案 0 :(得分:3)

您可以解构datecolor并迭代其余项。

const
    dataset = [{ date: '2018-01', color: 'red', value1: null, value2: null, value3: 2, value4: 6 }, { date: '2018-01', color: 'red', value1: 0, value2: 4, value3: null, value4: null }, { date: '2018-02', color: 'red', value1: null, value2: null, value3: 2, value4: 10 }, { date: '2018-02', color: 'red', value1: -9, value2: 0, value3: null, value4: null }, { date: '2019-01', color: 'blue', value1: null, value2: null, value3: 10, value4: 3 }, { date: '2019-01', color: 'blue', value1: -2, value2: 8, value3: null, value4: null }, { date: '2019-02', color: 'blue', value1: null, value2: null, value3: 20, value4: 2}, { date: '2019-02', color: 'blue', value1: 9, value2: 7, value3: null, value4: null }],
    result = Object.values(dataset.reduce((r, { date, color, ...rest }) => {
        const key = [date, color].join('|');
        if (!r[key]) r[key] = { date, color };
        Object.entries(rest).forEach(([k, v]) => {
            if ([undefined, null].includes(r[key][k])) r[key][k] = v;
        });
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

您可以使用<security-constraint> <web-resource-collection> <web-resource-name>Viewpoint Secure URLs</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> Array.reduce获得预期的结果。

Object.values
const dataset = [{date:'2018-01',color:'red',value1:null,value2:null,value3:2,value4:6},{date:'2018-01',color:'red',value1:0,value2:4,value3:null,value4:null},{date:'2018-02',color:'red',value1:null,value2:null,value3:2,value4:10},{date:'2018-02',color:'red',value1:-9,value2:0,value3:null,value4:null},{date:'2019-01',color:'blue',value1:null,value2:null,value3:10,value4:3},{date:'2019-01',color:'blue',value1:-2,value2:8,value3:null,value4:null},{date:'2019-02',color:'blue',value1:null,value2:null,value3:20,value4:2},{date:'2019-02',color:'blue',value1:9,value2:7,value3:null,value4:null},]

const mergeData = (data) => {
  const finalRes = data.reduce((res, obj)=>{
    const {date, color} = obj;
    const key = `${date}_${color}`;
    res[key] = {
      ...res[key],
      ...obj,
      value1: res[key]?.value1 || obj.value1,
      value2: res[key]?.value2 || obj.value2,
      value3: res[key]?.value3 || obj.value3,
      value4: res[key]?.value4 || obj.value4
    }
    return res;
  }, {});
  return Object.values(finalRes);
}

console.log(mergeData(dataset))

以下是一种通用方法,而不是将解决方案限制为.as-console-wrapper { max-height: 100% !important; }value1。同时使用Optional ChainingNullish coalescing确保value4不会覆盖null

0
const dataset = [{date:'2018-01',color:'red',value1:null,value2:null,value3:2,value4:6},{date:'2018-01',color:'red',value1:0,value2:4,value3:null,value4:null},{date:'2018-02',color:'red',value1:null,value2:null,value3:2,value4:10},{date:'2018-02',color:'red',value1:-9,value2:0,value3:null,value4:null},{date:'2019-01',color:'blue',value1:null,value2:null,value3:10,value4:3},{date:'2019-01',color:'blue',value1:-2,value2:8,value3:null,value4:null},{date:'2019-02',color:'blue',value1:null,value2:null,value3:20,value4:2},{date:'2019-02',color:'blue',value1:9,value2:7,value3:null,value4:null},]

const mergeData = (data) => {
  const finalRes = data.reduce((res, {date, color, ...rest}) => {
    const key = `${date}_${color}`;
    let newObj = {}
    Object.keys(rest).forEach(valKey => {
      newObj = {
        ...newObj,
        [valKey]:  res[key]?.[valKey] ?? rest[valKey] 
//check if the corresponding key is present in `res` object and if it's
//null or undefined then replace it with the value from the current object
//in the loop
      }
    })
    res[key] = {
      date,
      color,
      ...newObj
    }
    return res;
  }, {});
  return Object.values(finalRes);
}

console.log(mergeData(dataset))

答案 2 :(得分:0)

我们在reduce上使用dataset
创建一个空({})对象累加器(acc)。
我们使用键date + color
如果该键不存在,我们只需使用当前值(cv)来创建它。
如果是这样,我们在其中添加cv的{​​{1}}。

此后,我们采用创建的对象的值并将其分配给value

result
var dataset = [
  {date: '2018-01', color: 'red', value1: null, value2: null, value3: 2, value4: 6},
  {date: '2018-01', color: 'red', value1: 0, value2: 4, value3: null, value4: null},
  {date: '2018-02', color: 'red', value1: null, value2: null, value3: 2, value4: 10},
  {date: '2018-02', color: 'red', value1: -9, value2: 0, value3: null, value4: null},
  {date: '2019-01', color: 'blue', value1: null, value2: null, value3: 10, value4: 3},
  {date: '2019-01', color: 'blue', value1: -2, value2: 8, value3: null, value4: null},
  {date: '2019-02', color: 'blue', value1: null, value2: null, value3: 20, value4: 2},
  {date: '2019-02', color: 'blue', value1: 9, value2: 7, value3: null, value4: null}
];

var result=Object.values(dataset.reduce(
  (acc, cv) => {
    if(acc[cv.date+cv.color]==undefined) acc[cv.date+cv.color]=cv;
    else {
      acc[cv.date+cv.color].value1+=cv.value1;
      acc[cv.date+cv.color].value2+=cv.value2;
      acc[cv.date+cv.color].value3+=cv.value3;
      acc[cv.date+cv.color].value4+=cv.value4;
    }
    return acc;
  },{}
));

console.log(result);

答案 3 :(得分:0)

我首先将dataset中的对象按datecolor进行分组。然后,通过仅覆盖nullishnullundefined)值将单个组中的对象合并在一起。

在下面的示例中,我将groupBymergeWith的功能抽象为各自的功能。

const dataset = [
  {date: '2018-01', color: 'red', value1: null, value2: null, value3: 2, value4: 6},
  {date: '2018-01', color: 'red', value1: 0, value2: 4, value3: null, value4: null},
  {date: '2018-02', color: 'red', value1: null, value2: null, value3: 2, value4: 10},
  {date: '2018-02', color: 'red', value1: -9, value2: 0, value3: null, value4: null},
  {date: '2019-01', color: 'blue', value1: null, value2: null, value3: 10, value4: 3},
  {date: '2019-01', color: 'blue', value1: -2, value2: 8, value3: null, value4: null},
  {date: '2019-02', color: 'blue', value1: null, value2: null, value3: 20, value4: 2},
  {date: '2019-02', color: 'blue', value1: 9, value2: 7, value3: null, value4: null},
]

const result = Array
  .from(
    groupBy(({date, color}) => JSON.stringify([date, color]), dataset)
      .values()
  )
  .map(group => mergeWith((_, a, b) => a ?? b, ...group));

console.log(result);



function groupBy(fn, iterable) {
  const groups = new Map();
  for (const item of iterable) {
    const key = fn(item);
    if (!groups.has(key)) groups.set(key, []);
    groups.get(key).push(item);
  }
  return groups;
}

function mergeWith(fn, ...objects) {
  const merged = Object.create(null);
  for (const object of objects) {
    for (const key in object) {
      if (key in merged) {
        merged[key] = fn(key, merged[key], object[key]);
      } else {
        merged[key] = object[key];
      }
    }
  }
  return merged;
}