如何在数组中找到相似值(数字)并合并相似值?

how to find Similar values(number) in array and the merge similars?

我有示例数组,我想在数组中找到重复(相似)的数字然后合并。

var arr = [{
'title': 'abc',
'number': 1
},{
'title': 'def',
'number': 1
},{
'title': 'ghi',
'number': 2
}];

然后合并一定要像

var arr = [{
'title': ['abc', 'def'],
'number': 1
},{
'title': 'ghi',
'number': 2
}];

我的意思是重复的标题必须合并为一个,重复的必须删除。

最简单的方法之一是使用唯一键将数据缩减为 object 以捕获常见数据:

var obj = arr.reduce(function (p, c) {
  var key = c.number;

  // if the object doesn't exist, create a new one
  // and set it's value as a pre-filled object
  p[key] = p[key] || { title: [], number: key };

  // then add the title to the title array
  p[key].title.push(c.title);
  return p;
}, {});

然后使用 object 键上的 map 重新创建 object 数组:

var data = Object.keys(obj).map(function (el) {
  return { title: obj[el].title, number: el };
});

DEMO

不管里面有多少元素,这都会给你一个标题数组,这是正确的方法(见@thefourtheye 的评论)。

但是,如果您只想在标题数组中有两个或更多元素时才拥有一个数组,则可以稍微更改代码:

var data = Object.keys(obj).map(function (el) {
  var title = obj[el].title;
  return {
    title: title.length === 1 ? title[0] : title,
    number: el
  };
});

DEMO

这是一种使用临时对象的方法,该对象保存对数组的引用和结果数组本身。

具有相同 number 的重复 title 仅插入一次(如 { 'title': 'xxx', 'number': 42 })。

var arr = [{ 'title': 'xxx', 'number': 42 }, { 'title': 'xxx', 'number': 42 }, { 'title': 'abc', 'number': 1 }, { 'title': 'def', 'number': 1 }, { 'title': 'ghi', 'number': 2 }],
    result = arr.reduce(function (r, b) {
        if (b.number in r.o) {
            if (!(b.title in r.o[b.number])) {
                r.a[r.o[b.number].index].title.push(b.title);
                r.o[b.number][b.title] = true;
            }
            return r;
        }
        r.o[b.number] = { index: r.a.push({ title: [b.title], number: b.number }) - 1 };
        r.o[b.number][b.title] = true;
        return r;
    }, { o: {}, a: [] }).a;

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

此解决方案遍历元素,并过滤掉具有相同编号的第二个和后续元素,但在此之前将它们的标题添加到第一个匹配项。换句话说,它几乎完全符合您提出的 "algorithm",到

I mean duplicate's title must be merged into one and duplicate must be deleted.

array.filter(function(elt, idx) {
  var number = elt.number;
  var title  = elt.title;

  // Check if an element has a number that matches the current one.
  function sameNumber(elt) { return number === elt.number; }

  // Find the index of the first array element with the same number.
  var first = findIndex(array, sameNumber);

  // If this is the first, just pass it through the filter.
  if (idx === first) return true;

  // Otherwise, concatenate our title with the title of the first occurrence.
  array[first].title = [].concat(array[first].title, title);
}

其中 findIndex 是(如果可用也可以使用 Array#findIndex):

function findIndex(array, condition) {
  for (var i = 0; i < array.length; i++) {
    if (condition(array[i])) return i;
  }
  return -1;
}

如果您希望title始终是一个数组,即使该数字只出现一次,则将相关行更改如下:

  // If this is the first, just pass it through the filter.
  if (idx === first) { elt.title = [elt.title]; return true; }

  // Otherwise, concatenate our title with the title of the first occurrence.
  array[first].title.push(title);

这避免了必须创建一些其他 object-like 数据表示,然后再转换回数组格式。