如何在JavaScript中合并对象数组但是取消移位数组

时间:2017-09-13 19:49:43

标签: javascript arrays algorithm

我想合并这两个对象数组,但对于urls我想使用unshift来合并数组而不是替换。

这是一个例子

var arr1 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url1"],
  "ids": ["5748bf9ab58adb2f614da195"]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url2"],
  "ids": ["5743260055f979a31fa98971"]
}, {
  "keyword": "name3",
  "score": 0.4960953181766197,
  "urls": ["url4"],
  "ids": ["58c04cd5208b4945c3920cad"]
}, {
  "keyword": "name4",
  "score": 0.3337163443410707,
  "urls": ["url5"],
  "ids": ["573628c38e32eeb039377f7e"]
}];

var arr2 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url6"],
  "ids": [""]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url7"],
  "ids": [""]
}]

我希望结果是

[{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url6", "url1"],
  "ids": ["5748bf9ab58adb2f614da195"]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url7", "url2"],
  "ids": ["5743260055f979a31fa98971"]
}, {
  "keyword": "name3",
  "score": 0.4960953181766197,
  "urls": ["url4"],
  "ids": ["58c04cd5208b4945c3920cad"]
}, {
  "keyword": "name4",
  "score": 0.3337163443410707,
  "urls": ["url5"],
  "ids": ["573628c38e32eeb039377f7e"]
}];    

这是我的尝试,但结果将取代网址数组;

var a3 = arr1.concat(arr2).reduce((acc, x) => {
  acc[x.keyword] = Object.assign(acc[x.keyword] || {}, x);
  return acc;
}, {});
console.log(a3);

它将被合并urls。其他值将被覆盖。

6 个答案:

答案 0 :(得分:3)

您可以使用Map收集具有相同keyword的对象,并在必要时进行更新。此解决方案适用于任意数组的数组。



var array1 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url1"], ids: ["5748bf9ab58adb2f614da195"] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url2"], ids: ["5743260055f979a31fa98971"] }, { keyword: "name3", score: 0.4960953181766197, urls: ["url4"], ids: ["58c04cd5208b4945c3920cad"] }, { keyword: "name4", score: 0.3337163443410707, urls: ["url5"], ids: ["573628c38e32eeb039377f7e"] }],
    array2 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url6"], ids: [""] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url7"], ids: [""] }],
    map = new Map,
    result = [],
    fn = a => {
        if (map.has(a.keyword)) {
            map.get(a.keyword).urls.unshift(...a.urls);
            return;
        }
        map.set(a.keyword, a);
        result.push(a);
    };

[array1, array2].forEach(a => a.forEach(fn));

console.log(result);

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




答案 1 :(得分:1)

我更喜欢使用Map而不是reduce:

 const result = [], hash = new Map();

 arr1.concat(arr2).forEach( obj => {
   if( hash.has( obj.keyword ) ){
    hash.get( obj.keyword ).urls.push(...obj.urls);
   }else{
    hash.set( obj.keyword, obj);
    result.push( obj );
  }
 });

答案 2 :(得分:0)

在分配给新对象之前,可以将urls属性从对象中取出,如果不存在则将其添加回来,或者unshift添加到现有数组中,如果是存在

var arr1 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url1"],
  "ids": ["5748bf9ab58adb2f614da195"]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url2"],
  "ids": ["5743260055f979a31fa98971"]
}, {
  "keyword": "name3",
  "score": 0.4960953181766197,
  "urls": ["url4"],
  "ids": ["58c04cd5208b4945c3920cad"]
}, {
  "keyword": "name4",
  "score": 0.3337163443410707,
  "urls": ["url5"],
  "ids": ["573628c38e32eeb039377f7e"]
}];

var arr2 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url6"],
  "ids": [""]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url7"],
  "ids": [""]
}]
var a3 = arr1.concat(arr2).reduce((acc, x) => {
  let urls = x.urls; // store temporarily
  delete x.urls;     // delete before merging, to not overwrite

  acc[x.keyword] = Object.assign(acc[x.keyword] || {}, x);
  'urls' in acc[x.keyword] ? [].unshift.apply(acc[x.keyword].urls, urls) : acc[x.keyword].urls = urls;
  // ^      if exists                  unshift                                 or just add
  return acc;
}, {});
console.log(a3);

答案 3 :(得分:0)

对于arr1arr2没有任何副作用,您还需要某种克隆。

const a3 = ((a1, a2) => {
    const copy = item => {
        return {
            keyword: item.keyword,
            score: item.score,
            urls: item.urls.slice(),
            ids: item.ids.slice()
        };
    };

    a1 = a1.map(copy);

    const dictionary = a1.reduce((acc, item) => {
        acc[item.keyword] = item;
        return acc;
    }, {});

    a2.forEach(item => {
        if (dictionary[item.keyword]) {
            dictionary[item.keyword].urls = item.urls.concat(dictionary[item.keyword].urls);
        } else {
            const clone = copy(item);
            dictionary[clone.keyword] = clone;
            a1.push(clone);
        }
    });
    return a1;
})(arr1, arr2);

我用箭头作为函数简写/ const写了这个,但其余的是ES5

答案 4 :(得分:0)

我使用扩展运算符来合并数组,但unshift()也可以正常工作。

function mergeObjects(arrayA, arrayB) {
  var
    // Take all items in arrayA and place them in the result.
    result = arrayA.slice(0);
  // Iterate over all items in array B  
  arrayB.forEach(item => {
    var 
      // Check if there is an item in the result with the same keyword.
      resultItem = result.find(itemA => itemA.keyword === item.keyword);
    // When the keyword isn't yet in the result...
    if (resultItem === null) {
      // ... add it to the result
      result.push(item);
    } else {
      // ... or else add the urls from the current item to the urls of the result.
      resultItem.urls = [...item.urls, ...resultItem.urls];
    }
  });
  
  // Return the result array.
  return result;
}

var arr1 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url1"],
  "ids": ["5748bf9ab58adb2f614da195"]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url2"],
  "ids": ["5743260055f979a31fa98971"]
}, {
  "keyword": "name3",
  "score": 0.4960953181766197,
  "urls": ["url4"],
  "ids": ["58c04cd5208b4945c3920cad"]
}, {
  "keyword": "name4",
  "score": 0.3337163443410707,
  "urls": ["url5"],
  "ids": ["573628c38e32eeb039377f7e"]
}];

var arr2 = [{
  "keyword": "name",
  "score": 0.8992112752974006,
  "urls": ["url6"],
  "ids": [""]
}, {
  "keyword": "name1",
  "score": 0.39953909596222775,
  "urls": ["url7"],
  "ids": [""]
}];

console.log(mergeObjects(arr1, arr2));

答案 5 :(得分:0)

ES5优化方法(没有不必要的迭代,只是" 低级"处理):



var arr1 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url1"], ids: ["5748bf9ab58adb2f614da195"] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url2"], ids: ["5743260055f979a31fa98971"] }, { keyword: "name3", score: 0.4960953181766197, urls: ["url4"], ids: ["58c04cd5208b4945c3920cad"] }, { keyword: "name4", score: 0.3337163443410707, urls: ["url5"], ids: ["573628c38e32eeb039377f7e"] }],
    arr2 = [{ keyword: "name", score: 0.8992112752974006, urls: ["url6"], ids: [""] }, { keyword: "name1", score: 0.39953909596222775, urls: ["url7"], ids: [""] }],        
    len1 = arr1.length, c = 0, k = -1;
    
while (c < len1 && (l = arr2.length)) {
    for (i=0; i<l; i++) {
        if (arr1[c].keyword == arr2[i].keyword) {
	    arr1[c].urls.unshift(arr2[i].urls[0]);
	    k = i;
	    break;
	}
    }
    if (k >=0) {
        arr2.splice(k, 1);
        k = -1;
    }
    c++;
}

console.log(arr1);
&#13;
&#13;
&#13;

效果 比较结果(https://jsperf.com/map-vs-reduce-vs-while-loop):

enter image description here