使用相同的键合并数组中的javascript对象

时间:2015-11-22 00:48:54

标签: javascript arrays

array重组为output的最佳方法是什么?我需要将所有值键(无论是否为数组)合并到共享相同名称键的对象中。有一些类似的here,但这并不能回答我的问题,因为我也有数组。

var array = [
    {
        name: "foo1",
        value: "val1"
    }, {
        name: "foo1",
        value: [
            "val2",
            "val3"
        ]
    }, {
        name: "foo2",
        value: "val4"
    }
];

var output = [
    {
        name: "foo1",
        value: [
            "val1",
            "val2",
            "val3"
        ]
    }, {
        name: "foo2",
        value: [
            "val4"
        ]
    }
];

是的,我可以编写无休止的for循环和几个数组,但是有一个简单的(r)快捷方式吗?谢谢!

11 个答案:

答案 0 :(得分:24)

这是一个选项: -



var array = [{
  name: "foo1",
  value: "val1"
}, {
  name: "foo1",
  value: ["val2", "val3"]
}, {
  name: "foo2",
  value: "val4"
}];

var output = [];

array.forEach(function(item) {
  var existing = output.filter(function(v, i) {
    return v.name == item.name;
  });
  if (existing.length) {
    var existingIndex = output.indexOf(existing[0]);
    output[existingIndex].value = output[existingIndex].value.concat(item.value);
  } else {
    if (typeof item.value == 'string')
      item.value = [item.value];
    output.push(item);
  }
});

console.dir(output);




答案 1 :(得分:8)

这是实现这一目标的另一种方式:

var output = array.reduce(function(o, cur) {

  // Get the index of the key-value pair.
  var occurs = o.reduce(function(n, item, i) {
    return (item.name === cur.name) ? i : n;
  }, -1);

  // If the name is found,
  if (occurs >= 0) {

    // append the current value to its list of values.
    o[occurs].value = o[occurs].value.concat(cur.value);

  // Otherwise,
  } else {

    // add the current item to o (but make sure the value is an array).
    var obj = {name: cur.name, value: [cur.value]};
    o = o.concat([obj]);
  }

  return o;
}, []);

答案 2 :(得分:3)

使用lodash

var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"}];

function mergeNames (arr) {
    return _.chain(arr).groupBy('name').mapValues(function (v) {
        return _.chain(v).pluck('value').flattenDeep();
    }).value();
}

console.log(mergeNames(array));

答案 3 :(得分:1)

试试这个:



var array = [{name:"foo1",value:"val1"},{name:"foo1",value:["val2","val3"]},{name:"foo2",value:"val4"},{name:"foo2",value:"val5"}];

for(var j=0;j<array.length;j++){
  var current = array[j];
  for(var i=j+1;i<array.length;i++){
    if(current.name = array[i].name){
      if(!isArray(current.value))
        current.value = [ current.value ];
      if(isArray(array[i].value))
         for(var v=0;v<array[i].value.length;v++)
           current.value.push(array[i].value[v]);
      else
        current.value.push(array[i].value);
      array.splice(i,1);
      i++;
    }
  }
}

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}

document.write(JSON.stringify(array));
&#13;
&#13;
&#13;

答案 4 :(得分:1)

使用reduce:

var mergedObj = array.reduce((acc, obj) => {
    if (acc[obj.name]) {
       acc[obj.name].value = acc[obj.name].value.isArray ? 
       acc[obj.name].value.concat(obj.value) : 
       [acc[obj.name].value].concat(obj.value);

    } else {
      acc[obj.name] = obj;
    }

    return acc;
}, {});

let output = [];
for (let prop in mergedObj) {
  output.push(mergedObj[prop]) 
}

答案 5 :(得分:0)

const exampleObj = [{
  year: 2016,
  abd: 123
}, {
  year: 2016,
  abdc: 123
}, {
  year: 2017,
  abdcxc: 123
}, {
  year: 2017,
  abdcxcx: 123
}];
const listOfYears = [];
const finalObj = [];
exampleObj.map(sample => {    
  listOfYears.push(sample.year);
});
const uniqueList = [...new Set(listOfYears)];
uniqueList.map(list => {   
  finalObj.push({
    year: list
  });
});
exampleObj.map(sample => {    
  const sampleYear = sample.year;  
  finalObj.map((obj, index) => {     
    if (obj.year === sampleYear) {        
      finalObj[index] = Object.assign(sample, obj);       
    }  
  }); 
});

最终对象为[{“ year”:2016,“ abdc”:123,“ abd”:123},{“ year”:2017,“ abdcxcx”:123,“ abdcxc”:123}]

答案 6 :(得分:0)

这项工作也可以!

      var array = [
        {
          name: "foo1",
          value: "val1",
        },
        {
          name: "foo1",
          value: ["val2", "val3"],
        },
        {
          name: "foo2",
          value: "val4",
        },
      ];
      let arr2 = [];
      array.forEach((element) => { // remove duplicate name
        let match = arr2.find((r) => r.name == element.name);
        if (match) {
        } else {
          arr2.push({ name: element.name, value: [] });
        }
      });
      arr2.map((item) => {
        array.map((e) => {
          if (e.name == item.name) {
            if (typeof e.value == "object") { //lets map if value is an object
              e.value.map((z) => {
                item.value.push(z);
              });
            } else {
              item.value.push(e.value);
            }
          }
        });
      });
      console.log(arr2);

答案 7 :(得分:0)

试试这个:

    var array = [
      {
          name: "foo1",
          value: "val1"
      }, {
          name: "foo1",
          value: [
              "val2",
              "val3"
          ]
      }, {
          name: "foo2",
          value: "val4"
      }
  ];
  
  var output = [
      {
          name: "foo1",
          value: [
              "val1",
              "val2",
              "val3"
          ]
      }, {
          name: "foo2",
          value: [
              "val4"
          ]
      }
  ];

  bb = Object.assign( {}, array, output );

console.log(bb) ; 

答案 8 :(得分:0)

问这个问题已经有一段时间了,但我想我也会插话。对于像这样执行基本函数的函数,你会想要一遍又一遍地使用,如果我可以帮助它并使用浅层 Array.prototype 函数将函数开发为单行函数,我更愿意避免编写较长的函数和循环.map() 和其他一些 ES6+ 好东西,如 Object.entries()Object.fromEntries()。结合所有这些,我们可以相对轻松地执行这样的函数。

首先,我接受你传递给函数的许多对象作为一个 rest 参数,并在它前面加上一个空对象,我们将用来收集所有的键和值。

[{}, ...objs]

接下来,我使用 .map() 数组原型函数与 Object.entries() 配对来循环遍历每个对象的所有条目,以及每个包含的任何子数组元素,然后将空对象的键设置为如果尚未声明该值,则将新值推送到对象键(如果已声明)。

[{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]

最后,为了用它们包含的值替换任何单元素数组,我使用 .map()Object.entries() 在结果数组上运行另一个 Object.fromEntries() 函数,类似于我们所做的之前。

let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));

这将为您留下最终的合并对象,完全按照您的规定。

let a = {
  a: [1,9],
  b: 1,
  c: 1
}
let b = {
  a: 2,
  b: 2
}
let c = {
  b: 3,
  c: 3,
  d: 5
}

let getMergedObjs = (...objs) => Object.fromEntries(Object.entries([{},...objs].map((e,i,a) => i ? Object.entries(e).map(f => (a[0][f[0]] ? a[0][f[0]].push(...([f[1]].flat())) : (a[0][f[0]] = [f[1]].flat()))) : e)[0]).map(e => e.map((f,i) => i ? (f.length > 1 ? f : f[0]) : f)));

getMergedObjs(a,b,c); // { a: [ 1, 9, 2 ], b: [ 1, 2, 3 ], c: [ 1, 3 ], d: 5 }

答案 9 :(得分:0)

2021 版

var arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];

const result = arrays.reduce((acc, {name, value}) => {
  acc[name] ??= {name: name, value: []};
  if(Array.isArray(value)) // if it's array type then concat 
    acc[name].value = acc[name].value.concat(value);
  else
    acc[name].value.push(value);
  
  return acc;
}, {});

console.log(Object.values(result));

答案 10 :(得分:0)

这是一个使用 ES6 Map 的版本:

const arrays = [{ name: "foo1",value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2",value: "val4"}];

const map = new Map(arrays.map(({name, value}) => [name, { name, value: [] }])); 
for (let {name, value} of arrays) map.get(name).value.push(...[value].flat());
console.log([...map.values()]);