Javascript 下划线/lodash由多个属性唯一

Javascript 下划线/lodash由多个属性唯一,javascript,underscore.js,unique,lodash,Javascript,Underscore.js,Unique,Lodash,我有一个包含重复项的对象数组,我试图得到一个唯一列表,其中唯一性由对象属性的子集定义。比如说, {a:"1",b:"1",c:"2"} 我想在唯一性比较中忽略c 我可以做类似的事情 _.uniq(myArray,function(element) { return element.a + "_" + element+b}); 我希望我能做到 _.uniq(myArray,function(element) { return {a:element.a, b:element.b} }); 但这

我有一个包含重复项的对象数组,我试图得到一个唯一列表,其中唯一性由对象属性的子集定义。比如说,

{a:"1",b:"1",c:"2"}
我想在唯一性比较中忽略
c

我可以做类似的事情

_.uniq(myArray,function(element) { return element.a + "_" + element+b});
我希望我能做到

_.uniq(myArray,function(element) { return {a:element.a, b:element.b} });

但这不起作用。如果我比较多个属性,我是否可以这样做,或者是否需要创建对象的可比较表示?

不幸的是,似乎没有一种简单的方法可以做到这一点。除了为此编写自己的函数外,还需要返回一些可以直接比较相等性的内容(如第一个示例中所示)

一种方法是只
.join()
您需要的属性:

_.uniqBy(myArray, function(elem) { return [elem.a, elem.b].join(); });
或者,您可以使用或删除您不需要的任何内容。从那里,您可以将
..values
.join()
一起使用,甚至可以只使用
JSON.stringify

_.uniqBy(myArray, function(elem) {
    return JSON.stringify(_.pick(elem, ['a', 'b']));
});
请记住,就属性顺序而言,对象不是确定性的,因此您可能只希望坚持使用显式数组方法

另外,对于Lodash<4我确实认为join()方法仍然是最简单的方法。尽管在前面的解决方案中提出了一些问题,但我认为选择正确的分隔符是避免已识别陷阱(不同的值集返回相同的连接值)的关键。请记住,分隔符不需要是单个字符,它可以是您确信不会在数据本身中自然出现的任何字符串。我一直这样做,并且喜欢使用“~!$”作为我的分隔符。它还可以包括特殊字符,如\t\r\n等

如果包含的数据确实如此不可预测,那么最大长度可能是已知的,您只需在加入之前将每个元素填充到其最大长度即可。

使用Lodash的方法:

uniqWith(数组,[comparator])
此方法类似于
。.uniq
,只是它接受
比较器
,该比较器被调用以比较
数组
的元素。结果值的顺序由它们在数组中出现的顺序决定。使用两个参数调用比较器:(arrVal,othVal)

比较器
返回
true
时,这些项被视为重复项,只有第一次出现的项才会包含在新数组中


示例:
我有一个带有
纬度
经度
的位置列表,其中一些位置是相同的,我想查看唯一位置的列表:

const位置=[
{
名称:“办公室1”,
纬度:-30,
经度:-30
},
{
名称:“办公室2”,
纬度:-30,
经度:10
},
{
名称:“办公室3”,
纬度:-30,
经度:10
}
];
const uniqueLocations=qwith.uniqWith(
位置,
(位置A、位置B)=>
位置A.纬度===位置B.纬度&&
位置A.经度===位置B.经度
);
//结果有办公室1和办公室2

在@voithos和@Danail组合答案中有一个提示。我解决这个问题的方法是在数组中的对象上添加一个唯一的键

开始样本数据

const animalArray = [
  { a: 4, b: 'cat', d: 'generic' },
  { a: 5, b: 'cat', d: 'generic' },
  { a: 4, b: 'dog', d: 'generic' },
  { a: 4, b: 'cat', d: 'generic' },
];
在上面的示例中,我希望数组通过
a
b
是唯一的,但是现在我有两个对象,分别是
a:4
b:'cat'
。通过将a+b组合成一个字符串,我可以得到一个唯一的键来进行检查

{ a: 4, b: 'cat', d: 'generic', id: `${a}-${b}` }. // id is now '4-cat'
注意:显然,您需要映射数据,或者在创建对象时进行映射,因为您无法引用同一对象中对象的属性

现在比较简单

_.uniqBy(animalArray, 'id');

结果数组的长度为3,它将删除最后一个副本。

这是正确的答案


FYI
var result=uqby(list,v=>[v.id,v.sequence].join())

为什么要尝试第二次尝试?第一个正在工作,对吗?是的,第一个正在工作,但是必须进行字符串连接感觉有点不舒服。试图了解是否有更自然的方法来实现这一点。对象总是唯一的,因此您需要按单个属性值进行比较,而不是按整个对象进行比较。使用字符串比较可以处理某些数据,但不能处理其他数据,例如:使用如图所示的数字字符串,您可能会将{a:“1}与{a:1}.s_q.uniq([{a:“1”,b:“1”,c:“2”},{a:“1”,b:“1”,c:“2”},{a:“1”,c:“2”}),JSON.stringify);JSON顺序不能保证,但我不明白为什么这在单个浏览器中不起作用@dandavis我不想比较所有属性,只有使用
join(“”)
的属性的子集充满漏洞(例如
[1,23]
[12,3]
)。@muistooshort:很好-我想标准的逗号分隔的连接会更好。@voithos:但是如果数据包含逗号呢?或者如果一个数字没有被引用?@dandavis:我想你可以对数组执行
JSON.stringify
,而不是使用
join
。不过,实际上,只需重写
uniq
就可以更容易地考虑多个属性。lodash 4附带
.uniqWith(myArray,\u0.isEqual)
这应该是答案。这对我来说非常有效,谢谢!