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

时间:2016-01-12 12:24:14

标签: javascript array-merge

我有样本数组,我想在数组中找到重复(类似)数字,然后合并。

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

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

3 个答案:

答案 0 :(得分:1)

最简单的方法之一是使用唯一键将数据减少到对象以捕获常见的数据:

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

然后在对象键上使用map重新创建对象数组:

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

答案 1 :(得分:1)

此解决方案循环遍历元素,并使用相同的数字过滤掉第二个和后续元素,但在此之前将其标题添加到第一个匹配项。换句话说,它几乎完全遵循你提出的“算法”,

  

我的意思是必须将副本的标题合并为一个,并且必须删除副本。

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

这避免了必须创建一些其他类似对象的数据表示,然后转换回数组格式。

答案 2 :(得分:0)

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

仅使用相同的title复制number一次(例如{ '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>');