【问题标题】:Merge two unordered objects with different keys but same value?合并两个具有不同键但相同值的无序对象?
【发布时间】:2017-08-17 01:07:15
【问题描述】:

在 javascript 中合并 obj1 和 obj2 等对象以获取 obj3。

obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}]
obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}]

obj3 = [{fruit_name: 'apple', color: 'red', sweetness: 5},{fruit_name: 'banana', color:'yellow', sweetness: 4},{fruit_name: 'watermelon', color:'green', sweetness: 3}]

【问题讨论】:

  • 您的“对象”示例在语法上不正确。您是否打算将大括号类型 {/[ 交换?
  • 是的,我不小心交换了它们
  • 您的问题是什么?您只发布了一条说明。您是否尝试过自己解决问题?

标签: javascript arrays sorting


【解决方案1】:

不是一般的解决方案,但足以满足您的情况:

var obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}]
var obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}]

var obj3 = obj2.map(o => Object.assign({}, o, {'sweetness': obj1.find(p => p.fruit === o.fruit_name).sweetness}))

console.log(obj3)

【讨论】:

  • 你甚至可以使用object spread syntax来缩短代码
  • 这一个班轮解决方案很漂亮,因为我试图使用嵌套的 for 循环来解决问题。我在这里要求寻找更优雅的解决方案,仅此而已。
【解决方案2】:

您可以首先通过使用#forEach 合并相似对象来创建hashtable,然后使用@987654322提取所需的数组@函数 - 见下面的演示:

var obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}],
  obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}], hash = {};

// function to create a hashtable
function classify(e) {
   if(hash[e.fruit] || hash[e.fruit_name]) {
     Object.keys(e).forEach(function(c){
        hash[e.fruit || e.fruit_name][c] = e[c];
     });
   } else {
     hash[e.fruit_name || e.fruit] = e;
   }
}

// add to hash
obj1.forEach(classify);
obj2.forEach(classify);

// extract the result
var obj3 = Object.keys(hash).map(function(e){
  delete hash[e]['fruit'];
  return hash[e];
});

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

【讨论】:

  • 这也是一个不错的解决方案
  • 谢谢,这将适用于所有类似的数据结构 - 您只需要知道唯一标识数组中的元素的键(这里是 fruit 或 @ 987654330@)...
  • 我真的很喜欢这个解决方案,因为它很简单,并且正在积极使用它。但是,我有一个问题,因为它没有捕获 2 个具有相同键值的项目。示例:{fruit_name: 'apple', color: 'red'}, {fruit_name: 'apple', color: 'green'}。它只会列出最后一个(在本例中为绿色)。我在此问题上还有另一个问题:stackoverflow.com/questions/47638322/…
【解决方案3】:

您的数据结构不正确。不能将 "'fruit: 'watermelon'" (key, value pair) 保存在数组中。

会报错:Uncaught SyntaxError: Unexpected token :

我假设你想要做的是:

obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}]
  obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}]
  obj3 = [];
  
for (i = 0; i < obj1.length; i++) {
  for (j = 0; j < obj2.length; j++) {
    if (obj1[i].fruit === obj2[j].fruit_name) {
      var temp = {
        fruit_name: obj2[j].fruit_name,
        color: obj2[j].color,
        sweetness: obj1[i].sweetness
      }
      obj3.push(temp);
    }
  }
}

console.log(obj3);

【讨论】:

  • 我修复了这个例子
【解决方案4】:

将两个具有共享键的对象数组合并在一起的通用函数相当简单。最简单的方法是使用基于关联数组的映射,如下所示。请注意,您可以使用此例程来解决任何类似类型的问题,但它绝对适用于您的数据——请参阅最后链接的 JSFiddle。

(ETA:共享密钥仅添加一次,名称为 key1;如果您希望第二个密钥在输出中结束,只需将参数对交换给函数。)

obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}];
obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}];

function mergeObjectArrays(array1, key1, array2, key2) {
  var map = []; // an associative array/hashtable
  var arrayValue, mapValue, propertyNames, propertyName, propertyValue;

  // 1. Loop over one array, populating the map by each object's specified key
    for(var x = 0; x < array1.length; x++) {
    array1Value = array1[x];
    map[array1Value[key1]] = array1Value;
    map.push(array1Value);
  }

  // 2. Loop over the other array, matching on the provided keys
  for(var x = 0; x < array2.length; x++) {
    arrayValue = array2[x];
    mapValue = map[arrayValue[key2]];

    if (typeof(mapValue) != 'undefined') { // add all missing non-keyed properties to the mapped/merged object
      propertyNames = Object.keys(arrayValue);
      for (var y = 0; y < propertyNames.length; y++) {
          propertyName = propertyNames[y];
          if (propertyName != key1 && propertyName != key2) { // .. as that shared value is already added
            propertyValue = arrayValue[propertyName];
            mapValue[propertyName] = propertyValue;
          }
      }      
    }
    else { // it's missing from the mapping, so at least add it though it will be missing array1 data
      map[arrayValue[key2]] = arrayValue;
      map.push(arrayValue);
    }
  }

  return map;
}

var mergedArrays = mergeObjectArrays(obj1, 'fruit', obj2, 'fruit_name');

Here's a working sample.

【讨论】:

    【解决方案5】:
    let obj1 = [{fruit: 'watermelon', sweetness: 3},{fruit: 'banana', sweetness: 4},{fruit: 'apple', sweetness: 5}];
    let obj2 = [{fruit_name: 'apple', color: 'red'},{fruit_name: 'banana', color:'yellow'},{fruit_name: 'watermelon', color:'green'}];
    
    function regulate(a) {
      return a.map(v => {
        if (v.fruit) {
            v.fruit_name = v.fruit;
            delete v.fruit;
         }
         return v;
      });
    }
    
    
    let a = [].concat(regulate(obj1), regulate(obj2));
    
    let merged = [];
    a.reduce((m, v) => {
      let f = m.filter(v2 => v2.fruit_name === v.fruit_name);
      if (f.length > 0) {
        Object.assign(f[0], v);
      } else {
        m.push(v);
      }
      return m;
    }, merged);
    
    console.log(merged);
    

    【讨论】:

    • 我的解决方案是通用的,但是对于只有 2 个阵列的情况来说太浪费了......
    猜你喜欢
    • 2018-05-22
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2018-01-13
    • 1970-01-01
    • 2014-09-14
    相关资源
    最近更新 更多