如何创建一个只包含不重复元素的数组(即删除重复元素)?

32

我有这段代码:

var ar = [10,7,8,3,4,7,6];

function isin(n,a){
  for (var i=0;i<a.length;i++){
    if (a[i]== n) {
      var b = true;
      return b;
    } else {
      var c = false;
      return c;
   }
  }
}

function unique(a){
  var arr = [];
  for (var i=0;i<a.length;i++){
    if (!isin(a[i],arr)){
      arr.push(a[i]);
    }
  }

 return arr;
}

alert(unique(ar));

在这段代码中,我试图从原数组创建新的不重复的唯一数组。 但是我仍然得到了原始数组!我的错误在哪里?

18个回答

81

或者对于那些寻求一行命令(简单且实用)的人:

var a = ["1", "1", "2", "3", "3", "1"];
var unique = a.filter(function(item, i, ar){ return ar.indexOf(item) === i; });

这是正确的答案,因为它使用了标准和内置函数,而不是自己编写的解决方案。 - erapert
非常棒的回答。特别是ar(它也可以是I)与数组中的第一个匹配进行比较。 - Sander
@erapert 如果不必支持 IE 或古老的 Android 浏览器,我的下面答案中的 new Set() 是内置的。但我感到 Set() 受到阻碍,因为它很难进行谷歌搜索(SEO 的坏名称)。如果您的列表达到 1000 个项目,此答案可能会进行 100k-1mil 次比较操作(在indexOf()内部完成的工作)。这是很多 CPU 要做一些可能是 O(n)的事情(每个项目几个操作)。 - yzorg
@erapert 我的 unique() 的“inline”版本只是:[...new Set(list)] - yzorg

48

使用普通数组并返回关联数组的键(仅包含给定数组中的“唯一”值)更有效:

function ArrNoDupe(a) {
    var temp = {};
    for (var i = 0; i < a.length; i++)
        temp[a[i]] = true;
    var r = [];
    for (var k in temp)
        r.push(k);
    return r;
}

$(document).ready(function() {
    var arr = [10, 7, 8, 3, 4, 3, 7, 6];
    var noDupes = ArrNoDupe(arr);
    $("#before").html("Before: " + arr.join(", "));
    $("#after").html("After: " + noDupes.join(", "));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="before"></div>
<div id="after"></div>

注意:该函数不保留项目的顺序,因此如果这很重要,请使用不同的逻辑。
从IE9开始,在所有其他现代浏览器(例如Chrome、Firefox)中,可以通过使用Object.keys()方法使其更加高效:

function ArrNoDupe(a) {
    var temp = {};
    for (var i = 0; i < a.length; i++)
        temp[a[i]] = true;
    return Object.keys(temp);
}

$(document).ready(function() {
    var arr = [10, 7, 8, 3, 4, 3, 7, 6];
    var noDupes = ArrNoDupe(arr);
    $("#before").html("Before: " + arr.join(", "));
    $("#after").html("After: " + noDupes.join(", "));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="before"></div>
<div id="after"></div>

感谢wateriswet提醒我注意到这个。:)


你的例子是如何工作的??关联数组不能包含重复项吗??它是如何进行过滤的?? - DrStrangeLove
1
不,关联数组的键是唯一的,这是我方法的“核心”。没有“过滤器”..我只是将数组项分配为关联数组的键,然后读取键返回到新数组。 - Shadow The Spring Wizard
1
这太棒了! - Daniel
如果你返回Object.keys(temp)而不是循环遍历所有的键并创建一个新数组,你可以进一步提高速度! - Joe Thomas
@wateriswet 嗯,当我写答案时我并不知道这一点,而且它在IE8及以下版本中会失败 - 你会惊讶于仍在使用这些古老版本的人有多少。无论如何,值得将此添加到答案中,我会尽快尝试做到。谢谢! :) - Shadow The Spring Wizard


10

除了Josh Mc提供的使用过滤器的方法,你还可以在es6中使用箭头函数实用程序来使它更加简洁明了;

const a = ["1", "1", "2", "3", "3", "1"];
let unique = a.filter((it, i, ar) => ar.indexOf(it) === i);
// unique = [1, 2, 3]

7

编辑:请注意Daniel的警告。考虑到这一点和官方文档所说(如下),也许使用这个方法并不是一个好主意!


如果你碰巧使用jQuery,它的unique()函数可以实现这个功能:

var ar = [1, 2, 1, 2, 2, 3];    
ar = $.unique(ar);
console.log(ar);  // [3, 2, 1] 

文档中提到:

注意,这仅适用于DOM元素的数组,而不是字符串或数字。

...但是,当我使用jQuery 1.9.1进行测试时,它也适用于字符串和数字。无论如何,请仔细检查它是否可用,特别是在使用旧版本的jQuery时。


2
我曾经发现它可以处理一定数量的数字,但在某个点上会无缘无故停止工作。因此请谨慎使用。 - Daniel
谢谢你的警告 @Daniel!如果你还记得的话,你测试了多少个值? - user378704
@kiran.koduru 我真的不记得了。数组大小并不是很大,可能在20到300之间。无论如何,我建议使用接受答案中提供的方法:https://dev59.com/z2w05IYBdhLWcg3w72I0#6940176。如果有人需要,我还添加了一个CoffeeScript等效版本:https://dev59.com/z2w05IYBdhLWcg3w72I0#26827148。 - Daniel

3
因为您的isin方法在检查第一个元素后返回true或false。
请将其更改为以下内容:
function isin(n,a){
  for (var i=0;i<a.length;i++){
    if (a[i]== n){
    return true;

    }
  }
  return false;
}

2
你应该使用indexOf而不是你的isIn函数:
function unique(a){
  var arr = [];
  for (var i=0;i<a.length;i++){
    if ( arr.indexOf(a[i]) == -1){
        arr.push(a[i]);
    }
}

2

And with some ES5 fun...

function uniqueArray(array) {
    var temp = array.reduce(function(previous, current) {
        previous[current] = true;
        return previous;
    }, {});

    return Object.keys(temp);
}


1

我的错误在哪里??

就在这里:

... else {
      var c = false;
      return c;
   }

如果n与数组中的第一个元素不匹配,则会导致isin函数返回false。循环体在继续到下一个元素之前总是会返回一个值。

删除else子句并将return false移动到方法底部:

function isin(n,a){
    for (var i=0;i<a.length;i++) {
        if (a[i] == n)
            return true;

    return false;
}

请注意,isin方法可以立即实现(甚至可以被indexOf调用替换)。

1
也适用于数组 :-) 这里有一个链接,解释了它。 - aioobe
当然不适用于IE浏览器,但有解决方法。请参考此链接:https://dev59.com/MnI-5IYBdhLWcg3wpqMK。 - Shadow The Spring Wizard

1
您可以使用扩展运算符并利用集合提供的独特性。
const ar = [10, 7, 8, 3, 4, 7, 6];
const arUnique = [...new Set(ar)];

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