从数组中返回唯一值

3
如果我有一个如下的数组作为例子:
myArray = [1,4,5,1,5];
如何删除所有重复的值(在这个例子中是所有的1和5)并只返回唯一的元素(在这个例子中是4).
非常感谢您的帮助。

2
https://dev59.com/g2435IYBdhLWcg3wfgMf - Matt Pavelle
1
@MattPavelle:仔细阅读,这不是他们想要的。 - georg
4个回答

4

我认为

[1,4,5,1,5].filter(function(x, n, self) { 
    return self.indexOf(x) == self.lastIndexOf(x) 
})

使用下划线的基于哈希的更高效版本:

a =[1, 2, 3, 3, 4, 2, 1, 5]
uniqs = _.chain(a).countBy().pairs().filter(function(x) {
    return x[1] == 1
}).pluck(0).value()

或者纯JavaScript:

a = [1, 2, 3, 3, 4, 2, 1, 5]
hash = {}

a.forEach(function(x) {
    hash[x] = (Number(hash[x]) || 0) + 1
});

uniq = Object.keys(hash).filter(function(n) {
    return hash[n] == 1
});

请注意,这将把数组值转换为字符串(结果将是["4","5"])。
如果您希望对数组进行排序,也可以这样做:
a = [1, 2, 3, 3, 4, 2, 1, 5]

uniq = a.sort().filter(function(x, n, self) {
    return x != self[n - 1] && x != self[n + 1];
});

//[4, 5]

第二种和第三种方法有一个严重的限制,它们只适用于原始值 - 无法“唯一化”对象数组。第一个函数完美地解决了这个问题:
x = {x:1}; y = {y:1}; a = [x, y, x, x];
uniq = a.filter(function(x, n, self) { 
    return self.indexOf(x) == self.lastIndexOf(x) 
})
// {"y":1}

对于那些好奇的人,性能测试(在不同浏览器中表现不一致):http://jsperf.com/efficient-unique/2


2
这个方案可行,比朴素的搜索方法更高效(时间复杂度为O(nlog(n))而非O(n^2)),但是它会修改现有的数组。
var unique = [];

myArray.sort();

for (var i=0, j;i<myArray.length;i = j) {
    for (j=i+1;j<myArray.length && myArray[i] === myArray[j]; j++);

    if (j == i + 1) {
        unique.push(myArray[i]);
    }
}

// use unique

如评论中讨论的那样,您也可以利用一个对象来实现O(n)的解决方案,但是这种方法的执行时间在不同平台上变化很大(有时比上面的解决方案慢,有时更快)。

var unique = [], hash = {}, curr;

for (var i=0;i<myArray.length;i++) {
    curr = myArray[i];

    hash[curr] = (Number(hash[curr]) || 0) + 1;
}

for (var x in hash) {
    if (hash[x] === 1) {
        unique.push(x);
    }
}

// use unique

1
你有“更高效”的证明吗? - georg
1
@Matt:所以,“远远更有效率”显然是不正确的。我建议你更新帖子以反映这一点(并跳过大O符号,因为它也是错误的)。 - georg
1
@thg435:你运行的两个测试(假设是你)显示我的算法比朴素方法快两倍(1,900,000 vs 900,000ops/sec)。即使在这么小的数组中,这不是“更高效”吗?你能解释一下我的大O符号有什么问题吗? - Matt
1
@Matt:大O描述的是函数增长的方式,而不是它有多“快”。在这种情况下,所有这些“高效”和“大O”的讨论只会让人们感到困惑。对于小于10,000个项目的数组,两种方法之间没有实际区别。 - georg
1
@Matt:在 JavaScript 的上下文中,速度谈论很少有意义。在这种特殊情况下,它尤其毫无意义,因为如果你真的需要速度,问题可以使用哈希表在线性时间内轻松解决。你测试过吗? - georg
显示剩余5条评论

1
尝试这个:-
var arr = [1,4,5,1,5];
var sorted_arr = arr.sort(); 
var results = [];
for (var i = 0; i < arr.length - 1; i++) {
    if (sorted_arr[i + 1] !== sorted_arr[i]) {
        results.push(sorted_arr[i]);
    }
}

这不是原帖作者想要的。 - Matt
1
那仍然不能满足原帖的要求。 - Matt
1
你可能想要在下一个元素!==当前元素时进行push(),而不是当它们相等时进行。如果数组中有超过2个元素的出现次数(例如[1,1,1,2]),这种方法也会失败。 - Matt
你的意思是我应该写成 if (sorted_arr[i + 1] !== sorted_arr[i]) { results.push(sorted_arr[i]); 而不是 if (sorted_arr[i + 1] == sorted_arr[i]) { results.push(sorted_arr[i]); 吗? - Rahul Tripathi
1
这不是我的踩票。如果你修复了“如果数组中有超过2个元素的情况(例如[1,1,1,2])也会失败”的问题,我会给你一个赞。 - Matt
显示剩余2条评论

0

2
jQuery.unique 是用于 DOMNodes 的,根据文档说明:“对 DOM 元素数组进行排序”。 - Matt

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