【问题标题】:Merge JavaScript objects in array with same key合并具有相同键的数组中的 JavaScript 对象
【发布时间】:2015-11-22 00:48:53
【问题描述】:

从共享一个键的 JavaScript 对象中合并数组内容的最佳方法是什么?

如何将下面示例中的array 重组为output?在这里,所有value 键(无论是否为数组)都被合并到共享相同name 键的所有对象中。

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

【问题讨论】:

  • array {name:"foo1",value:"val1"} 将是{name:"foo1",value:["val1"]}
  • @BG101 不,它不是一个数组,但如果有帮助,我可以提前完成
  • 你试过使用 jQuery 的 extend() 方法吗?或者您是否正在尝试编写自己的合并脚本?所以可能是这样的:var newArray = $.extend({}, array, output);
  • 您是否有尝试合并内容的特定方式,或者$.extend() 就足够了?
  • @ZachPerkitny 我不确定 $.extend() 是否足够,因为我必须处理键值内的数组。

标签: javascript arrays


【解决方案1】:

这是一种选择:-

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

【讨论】:

  • 我的 keyvalue 名称不同。我很困惑,因为这里输入对象中的value 名称是value,而您在forEach 循环中采用的参数名称也被命名为值。请澄清我的困惑。谢谢。
  • 抱歉@ArpitMeena,现在才在 cmets 中看到您的请求。我已将其更改为 item 以在将来提供帮助。
  • 如果我有一个包含多个对象的数组都共享一个相同的键,但是这个键是未知的,例如一个对象结构是{ "127.0.0.1" : 1, "127.0.0.2" : 1, "127.0.0.3" : 1, "127.0.0.4" : 1, },第二个对象是{ "127.0.0.1" : 1000, "127.0.0.2" : 1000, "127.0.0.3" : 1000, "127.0.0.4" : 1000, },如何将它们合并为输出,就像{"127.0.0.1": 1, "my-custom-key": 1000}, second obj etc.... 这样的东西。 ps 值可能不同,我只是举了一个简单的例子。
  • 你是救生员!!
【解决方案2】:

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

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

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;
}, []);

console.log(output);

【讨论】:

  • 如果我需要将值添加为对象该怎么办?
【解决方案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));

【讨论】:

  • 简化版和现在也采摘应该是地图:const mergeNames = arr => _.chain(arr).groupBy('name').mapValues(v => _.chain(v).map('value').flattenDeep()).value(); console.log(mergeNames(array));
  • 数据在 '2021-04-14' 到来: LodashWrapper { wrapped: LazyWrapper { wrapped: [LodashWrapper], 动作: [Array], dir: 1, filtered: false, iteratees: [Array], takeCount: 4294967295, views: [] }, actions: [ [Object] ], chain: true, index: 0, values: undefined } 这种格式。如何将其转换为数组格式?
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    这是一个使用 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()]);

    【讨论】:

      【解决方案6】:

      试试这个:

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

      【讨论】:

      • 这是万无一失的,但这是我试图绕过的传统暴力方法。
      • 是的,但我没有使用“无限”循环 :-),我只使用了两个循环,更重要的是,我直接在 array 变量上工作,无需另一个 output 变量这使其内存效率更高。不过我也很喜欢BG101和湖南的两个回答,所以点了赞。
      【解决方案7】:

      使用减少:

      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]) 
      }
      

      【讨论】:

        【解决方案8】:
        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}]

        【讨论】:

          【解决方案9】:

          这也是工作!

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

          【讨论】:

          • 如何添加 foo1 的值?基本上将val1, val2, and val3 添加到 1 个值中?
          • 我正在使用 temp arr2 保存值,然后再次映射它们以查看是一个对象,然后我在其上创建一个数组,如果不是对象/数组,我将值推送给它@ jedLancer
          【解决方案10】:

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

          首先,无论您传递给函数的多少对象作为休息参数,我都会在其前面加上一个空对象,我们将使用它来收集所有键和值。

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

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

          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 }

          【讨论】:

            【解决方案11】:

            使用 lodash "uniqWith"。如下图

            let _ = require("lodash");
            
            var array = [
              { name: "foo1", value: "1" },
              { name: "foo1", value: "2" },
              { name: "foo2", value: "3" },
              { name: "foo1", value: "4" }
            ];
            
            let merged = _.uniqWith(array, (pre, cur) => {
              if (pre.name == cur.name) {
                cur.value = cur.value + "," + pre.value;
                return true;
              }
              return false;
            });
            
            console.log(merged);
            // output:  [{ name: "foo1", value: "1,2,4" }, { name: "foo2", value: "3" }];
            
            
            

            【讨论】:

              【解决方案12】:

              试试这个:

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

              【讨论】:

                【解决方案13】:

                const array = [{ name: "foo1", value: "val1" }, {name: "foo1", value: ["val2", "val3"] }, {name: "foo2", value: "val4"}];
                const start = array.reduce((object, {name}) => ({...object, [name]: []}), {});
                const result = array.reduce((object, {name, value}) => ({...object, [name]: [object[name], [value]].flat(2)}), start);
                const output = Object.entries(result).map(([name, value]) => ({name: name, value: value}));
                console.log(output);

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-10-09
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-12-16
                  • 2019-08-02
                  • 2022-11-01
                  • 1970-01-01
                  • 2016-08-21
                  相关资源
                  最近更新 更多