从数组中过滤具有给定键相同值的对象

3

假设我们有一个看起来像这样的数组:

[
    {
        id: 0,
        name: 'A'
    },
    {
        id: 1,
        name:'A'
    },
    {
        id: 2,
        name: 'C'
    },
    {
        id: 3,
        name: 'B'
    },
    {
        id: 4,
        name: 'B'
    }
]

我希望只保留那些在“name”键上具有相同值的对象,因此输出结果看起来像这样:
[
    {
        id: 0,
        name: 'A'
    },
    {
        id: 1,
        name:'A'
    },
    {
        id: 3,
        name: 'B'
    },
    {
        id: 4,
        name: 'B'
    }
]

我想使用lodash,但是我没有找到适合这种情况的方法。


所以,你想保留那些在多个对象中存在“name”值的对象,对吗? - sanjiv saini
你能澄清一下吗?你只想保留那些在数组中至少存在两次的name属性的对象吗?还是说只保留连续两个具有相同name属性的对象对? - Sebastian Simon
我只想保留数组中名称至少出现两次的对象。 - sympi
@sympi 啊,好的,在这种情况下,Rajesh的答案应该是解决方案,尽管它没有使用lodash。 - Sebastian Simon
列表中每个元素的顺序重要吗?如果id:1(名称:'A')变成了id:5,会发生什么? - Rickard Elimää
4个回答

9
您可以尝试以下方法:

思路:

  • 遍历数据并创建一个姓名列表,其中包含它们出现的次数。
  • 再次遍历数据,并过滤掉任何计数小于2的对象。

var data = [{ id: 0, name: 'A' }, { id: 1, name: 'A' }, { id: 2, name: 'C' }, { id: 3, name: 'B' }, { id: 4, name: 'B' }];

var countList = data.reduce(function(p, c){
  p[c.name] = (p[c.name] || 0) + 1;
  return p;
}, {});

var result = data.filter(function(obj){
  return countList[obj.name] > 1;
});

console.log(result)


说实话,我确实检查了你的答案(不止一次),但像往常一样,这仍然让我有些困惑。我会再读几遍的。;-) 还会尝试用一个循环来完成。谢谢你的指出。 - Rajesh
1
它适用于空数组,并且如果以后有效,则使用 update 获取一个元素。concat 过滤空元素。 - Nina Scholz

5

一种 lodash 的方法,可能(或可能不)更容易跟随步骤:

const originalArray = [{ id: 0, name: 'A' }, { id: 1, name: 'A' }, { id: 2, name: 'C' }, { id: 3, name: 'B' }, { id: 4, name: 'B' }];

const newArray =
      _(originalArray)
       .groupBy('name') // when names are the same => same group.  this gets us an array of groups (arrays)
        .filter(group => group.length == 2) // keep only the groups with two items in them
        .flatten() // flatten array of arrays down to just one array
        .value();
        
console.log(newArray)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>


4

使用array.filter和array.some的更短解决方案:

var data = [ { ... }, ... ];  // Your array
var newData = data.filter((elt, eltIndex) => data.some((sameNameElt, sameNameEltIndex) => sameNameElt.name === elt.name && sameNameEltIndex !== eltIndex));
console.log("new table: ", newTable);

不错的解决方案,但是小尺寸(长行)并没有真正帮助可读性。使用some调用的lambda函数可以提取为一个命名函数吗? - jonahe
是的,可以使用命名函数作为这些回调函数。 - Faly

2
您可以使用哈希表和单个循环来映射对象,或者只使用一个空数组,然后将结果与空数组连接起来。

var data = [{ id: 0, name: 'A' }, { id: 1, name: 'A' }, { id: 2, name: 'C' }, { id: 3, name: 'B' }, { id: 4, name: 'B' }],
    hash = Object.create(null),
    result = Array.prototype.concat.apply([], data.map(function (o, i) {
        if (hash[o.name]) {
            hash[o.name].update && hash[o.name].temp.push(hash[o.name].object);
            hash[o.name].update = false;
            return o;
        }
        hash[o.name] = { object: o, temp: [], update: true };
        return hash[o.name].temp;
    }));

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接