获取JavaScript数组中的所有唯一值(删除重复项)

Mot*_*tie 1273 javascript arrays unique

我有一系列数字,我需要确保它们是唯一的.我在互联网上找到了下面的代码片段,它的工作情况很好,直到数组中的数字为零.我发现这个其他脚本在SO上看起来几乎就像它,但它不会失败.

所以为了帮助我学习,有人可以帮我确定原型脚本出错的地方吗?

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}
Run Code Online (Sandbox Code Playgroud)

重复问题的更多答案:

类似的问题:

TLi*_*dig 2321

使用JavaScript 1.6/ECMAScript 5,您可以通过filter以下方式使用Array 的本机方法来获取具有唯一值的数组:

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
Run Code Online (Sandbox Code Playgroud)

本机方法filter将循环遍历数组,只留下那些通过给定回调函数的条目onlyUnique.

onlyUnique检查,如果给定的值是第一次发生.如果没有,则必须是重复的,不会被复制.

此解决方案无需任何额外的库,如jQuery或prototype.js.

它适用于具有混合值类型的数组.

对于旧浏览器(<ie9),它不支持本机方法filter,indexOf您可以在MDN文档中找到filterindexOf的解决方法.

如果要保留最后一次出现的值,请简单替换indexOflastIndexOf.

使用ES6可以缩短到这个:

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 

// unique is ['a', 1, 2, '1']
Run Code Online (Sandbox Code Playgroud)

感谢Camilo Martin的评论提示.

ES6有一个本机对象Set来存储唯一值.要获得具有唯一值的数组,您现在可以执行以下操作:

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)]; 

// unique is ['a', 1, 2, '1']
Run Code Online (Sandbox Code Playgroud)

Set获取可迭代对象(如Array)的构造函数,以及扩展运算符...将该集转换回Array.感谢Lukas Liese的评论提示.

  • `let unique_values = [...new Set(random_array)];` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set (120认同)
  • 不幸的是,这个解决方案运行得慢得多.你循环两次,一次使用过滤器,一次使用索引 (42认同)
  • 为了避免任何新手被性能影响吓跑,请考虑“慢得多”很可能是纳秒。如果您的数组相对较小(数百个或更少),那么出于性能之外的原因(即可读性和可维护性),使用像这样的简洁的一次性版本是有好处的。但套装版本相当漂亮和简洁。 (29认同)
  • 比较 .filter+indexOf 和 Chrome 100 中的 Set-approach 的性能表明,对于数字和长度为 0 到 120 的数组,filter-approach 甚至更快。数组长度为 200 时,过滤方法比 Set 多花费 50% 的时间(6 微秒与 9 微秒)。对于 5000 个元素,过滤操作需要超过 3 毫秒,而 Set 仍然可以在 173 微秒内处理我的示例。所以“慢得多”实际上取决于用例。如果有人感兴趣,我可以将数据作为单独的问答发布。 (23认同)
  • 在现代JS中:`.filter((v,i,a)=> a.indexOf(v)== i)`(胖箭头符号). (21认同)
  • @JackFranzen比什么慢?来自_Rafael_的解决方案?_Rafaels_解决方案不适用于混合类型数组.对于我的例子`['a',1,'a',2,'1']`你会得到`['a',1,2]`.但这不是我的预期.顺便说一句,慢得多是非常相对的. (16认同)
  • “自我”不起作用。 (5认同)
  • 有关更详细的答案,包括许多可能性 - 例如排序优先,以及处理不同的数据类型 - 请参阅http://stackoverflow.com/a/9229821/368896 (4认同)
  • 为什么需要`[...` ... `]`?`new Set(myArray)` 本身似乎具有相同的行为 (3认同)
  • 虽然迟到了,但是“let unique_values = Array.from(new Set(random_array));”在我看来更容易阅读。 (3认同)
  • @BradGreens。由于TypeScript是强类型的,因此您无法进行这种黑客攻击。尝试`Array.from(new Set(myArray));` (2认同)
  • 错误,猜测新事物不向后兼容:{ "message": "Uncaught TypeError: self.indexOf is not a function", "filename": "https://stacksnippets.net/js", "lineno": 13, “科诺”:15 } (2认同)

A.T*_*.T. 766

更新了ES6/ES2015的答案:使用Set,单行解决方案是:

var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))
Run Code Online (Sandbox Code Playgroud)

哪个回报

[4, 5, 6, 3, 2, 23, 1]
Run Code Online (Sandbox Code Playgroud)

正如le_m建议的那样,这也可以使用spread运算符缩短,比如

var uniqueItems = [...new Set(items)]
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果使用`Set`并添加对象而不是原始值,它将包含对象的唯一*引用*.因此,`let s = new Set([{Foo:"Bar"},{Foo:"Bar"}]);`中的集合`s`将返回:`Set {{Foo:'Bar'},{ Foo:'Bar'}}`这是一个`Set`,它包含对包含相同值的对象的唯一对象引用.如果你写'let o = {Foo:"Bar"};`然后创建一个带有两个*引用*的集合,如下所示:`let s2 = new Set([o,o]);`,那么s2将是`设置{{Foo:'Bar'}}` (30认同)
  • 请注意,内部数组不起作用`Array.from(new Set([[1,2],[1,2],[1,2,3]])) (8认同)
  • 如果有人想知道,这也适用于字符串,例如 [...new Set(["apple","apple","orange"])] 结果为 ['apple', 'orange'] 。伟大的! (6认同)
  • 与`myArray.filter((v,i,a)=&gt; a.indexOf(v)=== i);'相比,该解决方案的性能如何? (2认同)
  • 新的测试用例https://jsperf.com/array-filter-unique-vs-new-set/1似乎是“ new Set”的奖杯 (2认同)
  • 在 Typescript 中,使用 Array.from( new Set( items ) )` (2认同)

Max*_*rov 139

我意识到这个问题已有30多个答案.但我先阅读了所有现有的答案并进行了自己的研究.

我将所有答案分成4个可能的解决方案:

  1. 使用新的ES6功能: [...new Set( [1, 1, 2] )];
  2. 使用对象{ }来防止重复
  3. 使用辅助数组 [ ]
  4. 使用 filter + indexOf

以下是答案中的示例代码:

使用新的ES6功能: [...new Set( [1, 1, 2] )];

function uniqueArray0(array) {
  var result = Array.from(new Set(array));
  return result    
}
Run Code Online (Sandbox Code Playgroud)

使用对象{ }来防止重复

function uniqueArray1( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 
Run Code Online (Sandbox Code Playgroud)

使用辅助数组 [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}
Run Code Online (Sandbox Code Playgroud)

使用 filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}
Run Code Online (Sandbox Code Playgroud)

我想知道哪一个更快.我已经制作了样本Google表格以测试功能.注意:ECMA 6在Google表格中不可用,因此我无法对其进行测试.

这是测试的结果: 在此输入图像描述

我希望看到使用object的代码{ }会赢,因为它使用hash.所以我很高兴测试在Chrome和IE中显示了该算法的最佳结果.感谢@rab 代码.

  • Makrov,所以 `uniqueItems = [...new Set(items)]` 似乎是所有方法中最快、最简洁的? (11认同)
  • 您非常适合进行这次测试比较,谢谢,我现在使用包含数十万个条目的数组进行了测试,实际上 `uniqueItems = [...new Set(items)]` 似乎是最快的 (3认同)
  • @ fletchsod,数字是运行代码的时间(以毫秒为单位)。 (2认同)
  • 您的解决方案仅处理基元,它不适用于对象,您需要 JSON.stringify 哈希中的 v (2认同)

kor*_*dge 131

您也可以使用underscore.js.

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
Run Code Online (Sandbox Code Playgroud)
<script src="http://underscorejs.org/underscore-min.js"></script>
Run Code Online (Sandbox Code Playgroud)

将返回:

[1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

  • @superluminary我知道这就是为什么我说请**做**这个.接受的解决方案建议修改Array原型.不要那样做. (21认同)
  • 请这样做.不要把东西插到Array原型上.请. (20认同)
  • @JacobDalton请不要这样做.没有必要为一个小工作添加额外的库,可以用`array = [... new Set(array)]来完成. (13认同)
  • @JacobDalton - 这不是扩展Array原型.它在_对象中被命名空间. (4认同)
  • @JacobDalton在您自己的代码中修改原型没有问题。如果有任何代码使用`for(数组中的var i)`,那应该扔掉。也就是说,库可能不应该与原型混淆,因为它们可能用在遗留/损坏的环境中,在该环境中,凌晨4点醉酒的实习生编写了与修改数组原型的干净JS一起使用时可能会损坏的代码。 (2认同)

mdm*_*ndo 103

使用 删除重复项Set

Array有重复项

const withDuplicates = [2, 2, 5, 5, 1, 1, 2, 2, 3, 3];
Run Code Online (Sandbox Code Playgroud)

使用 Set 获取没有重复项的新数组

const withoutDuplicates = Array.from(new Set(withDuplicates));
Run Code Online (Sandbox Code Playgroud)

较短的版本

const withoutDuplicates = [...new Set(withDuplicates)];
Run Code Online (Sandbox Code Playgroud)

结果:[2, 5, 1, 3]

  • 完全重复了在此之前几年给出的其他答案。 (2认同)

小智 69

使用ES6新集

var array = [3,7,5,3,2,5,2,7];
var unique_array = [...new Set(array)];
console.log(unique_array);    // output = [3,7,5,2]
Run Code Online (Sandbox Code Playgroud)

使用For 循环

var array = [3,7,5,3,2,5,2,7];

for(var i=0;i<array.length;i++) {
    for(var j=i+1;j<array.length;j++) {
        if(array[i]===array[j]) {
            array.splice(j,1);
        }
    }
}
console.log(array); // output = [3,7,5,2]
Run Code Online (Sandbox Code Playgroud)


Vam*_*msi 62

One Liner,Pure JavaScript

使用ES6语法

list = list.filter((x, i, a) => a.indexOf(x) == i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

使用ES5语法

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});
Run Code Online (Sandbox Code Playgroud)

浏览器兼容性:IE9 +

  • @Spets它有二次成本,因此它不是最好的答案 (9认同)

Mot*_*tie 51

我后来发现了一个使用jQuery的好方法

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});
Run Code Online (Sandbox Code Playgroud)

注意:这段代码是从保罗爱尔兰人的鸭子冲击帖中提取 - 我忘了给予赞誉:P

  • 一个简洁的解决方案,但调用inArray比调用hasOwnProperty效率低. (8认同)

Tor*_*ker 49

ES6的最短解决方案: [...new Set( [1, 1, 2] )];

或者,如果要修改Array原型(如原始问题中所示):

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};
Run Code Online (Sandbox Code Playgroud)

EcmaScript 6目前仅在现代浏览器中部分实现(2015年8月),但Babel已经变得非常流行,可以将ES6(甚至是ES7)转换回ES5.那样你今天就可以编写ES6代码了!

如果你想知道...它意味着什么,它就叫做传播算子.来自MDN:«扩展运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组文字)的地方扩展表达式».因为Set是可迭代的(并且只能具有唯一值),所以扩展运算符将展开Set以填充数组.

学习ES6的资源:

  • 你可以做得更短,用'a = [... Set(a)]`,但是,无论如何,这只是Firefox,现在. (3认同)

Ped*_* L. 35

最简单的解决方案

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);
Run Code Online (Sandbox Code Playgroud)

要么:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));
Run Code Online (Sandbox Code Playgroud)

  • 请注意,IE10及更低版本不支持此功能.请注意,IE11 +和Safari提供有限的支持(甚至不确定以上示例是否有效)https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set (4认同)

Joe*_*e50 32

最简单,最快速(以Chrome方式)执行此操作的方式:

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}
Run Code Online (Sandbox Code Playgroud)

只需遍历数组中的每个项目,测试该项目是否已在列表中,如果不是,则推送到返回的数组.

根据jsPerf的说法,这个功能是我能在任何地方找到的最快的功能- 随意添加你自己的功能.

非原型版:

function uniques(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}
Run Code Online (Sandbox Code Playgroud)

排序

当还需要对数组进行排序时,以下是最快的:

Array.prototype.sortUnique = function() {
    this.sort();
    var last_i;
    for (var i=0;i<this.length;i++)
        if ((last_i = this.lastIndexOf(this[i])) !== i)
            this.splice(i+1, last_i-i);
    return this;
}
Run Code Online (Sandbox Code Playgroud)

或非原型:

function sortUnique(arr) {
    arr.sort();
    var last_i;
    for (var i=0;i<arr.length;i++)
        if ((last_i = arr.lastIndexOf(arr[i])) !== i)
            arr.splice(i+1, last_i-i);
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

在大多数非Chrome浏览器中,这也比上述方法更快.

  • 好吧,实际上您在`unique` 函数中实现的算法具有O(n^2) 复杂度,而`getUnique` 中的算法是O(n)。第一个在小数据集上可能更快,但是你怎么能用数学来争论:) 如果你在一个数组上运行它,比如 1e5 个唯一项,你可以确保后者更快 (4认同)

coc*_*cco 30

只有表现!这段代码可能比这里的所有代码快10倍*适用于所有浏览器,并且内存影响最小....等等

如果你不需要重用旧的数组;顺便说一下,在你将它转换为唯一之前做必要的其他操作,这可能是最快的方法,也很短.

var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];
Run Code Online (Sandbox Code Playgroud)

然后你可以试试这个

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];

function toUnique(a, b, c) { //array,placeholder,placeholder
  b = a.length;
  while (c = --b)
    while (c--) a[b] !== a[c] || a.splice(c, 1);
  return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]
Run Code Online (Sandbox Code Playgroud)

我想出了这个函数阅读这篇文章......

http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

我不喜欢for循环.它有许多参数.我喜欢while--循环.虽然是所有浏览器中最快的循环,除了我们都非常喜欢的那个... chrome.

无论如何,我写了第一个使用while的函数.是的,它比文章中的函数快一点.但还不够.unique2()

下一步使用现代js.Object.keys 我用js1.7的Object.keys替换了另一个for循环...更快更短(在chrome中快了2倍);).不够!.unique3().

在这一点上,我正在思考我在我独特的功能中真正需要什么.我不需要旧的阵列,我想要一个快速的功能.所以我用2循环+拼接.unique4()

没用说我印象深刻.

chrome:通常每秒150,000次操作跃升至每秒1,800,000次操作.

即: 80,000 op/s vs 3,500,000 op/s

ios: 18,000 op/s vs 170,000 op/s

safari: 80,000 op/s vs 6,000,000 op/s

证明 http://jsperf.com/wgu或更好地使用console.time ... microtime ......无论如何

unique5() 只是为了告诉你如果要保留旧数组会发生什么.

Array.prototype如果你不知道你在做什么,请不要使用.我刚做了很多副本和过去.使用Object.defineProperty(Array.prototype,...,writable:false,enumerable:false}):如果你想创建一个本地prototype.example /sf/answers/1432411501/

演示 http://jsfiddle.net/46S7g/

注意:此操作后,您的旧阵列将被销毁/成为唯一的阵列.

如果你不能阅读上面的代码问,请阅读一本javascript书或这里有一些关于更短代码的解释./sf/answers/1494712271/

有些人正在使用indexOf ...不要... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

对于空数组

!array.length||toUnique(array); 
Run Code Online (Sandbox Code Playgroud)

  • 在node.js上测试,有一个100k的Urls数组(字符串).结果比underscore.js _.uniq慢2倍......虽然一个单独的jsperf同意你(http://jsperf.com/uniq-performance/5),但我很失望:( (4认同)
  • 你没有在jsperf中正确测试...在你的例子中你每次都定义了这个函数......但是已经定义了underscore.js函数..这会惩罚我的函数.另外我应该说的是,如果你使用混合变量(字符串和数字),你应该用[b]替换a [b]!== a [c]!= a [c] (3认同)
  • 我不确定jsPerf是否正确,但是似乎Reduce替代(对我来说更容易理解)比您的解决方案快94%。https://jsperf.com/reduce-for-distinct编辑:在chrome上,您的速度较慢,在Edge上则相同,而在Firefox上则更快。 (2认同)
  • **仅适用于小阵列/低重复百分比**。每次找到非唯一对象时,引擎将被迫通过以下方式将其余所有元素“向左”移动:1)遍历它们2)读取它们3)将它们写入新位置。然后,它也用一个拼接的元素创建了一个新数组,并将其返回为结果...算法随着较大的数组/更频繁的重复项而迅速退化。对于大小为1000-&gt; 10000-&gt; 50000且重复次数约为40%的阵列,平均耗时将为2-&gt; 775-&gt; 19113 ms。(在Chrome中,大小更改为1-&gt; x10-&gt; x5,时间更改为1-&gt; x10-&gt; x25)。 (2认同)

Set*_*day 27

这里的许多答案可能对初学者没用.如果难以对数组进行重复数据删除,他们真的会知道原型链,甚至是jQuery吗?

在现代浏览器中,一个简洁明了的解决方案是将数据存储在Set中,该Set设计为唯一值列表.

const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));
Run Code Online (Sandbox Code Playgroud)

Array.from让你可以很方便地访问所有的真棒方法(特征),数组必须是设置转换回阵列有用.还有其他方法可以做同样的事情.但是你可能根本不需要Array.from,因为集合有很多有用的功能,比如forEach.

如果您需要支持旧的Internet Explorer,因此无法使用Set,那么一种简单的技术是将项目复制到新阵列,同时事先检查它们是否已经在新阵列中.

// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];

// Go through each car, one at a time.
cars.forEach(function (car) {
    // The code within the following block runs only if the
    // current car does NOT exist in the uniqueCars list
    // - a.k.a. prevent duplicates
    if (uniqueCars.indexOf(car) === -1) {
        // Since we now know we haven't seen this car before,
        // copy it to the end of the uniqueCars list.
        uniqueCars.push(car);
    }
});
Run Code Online (Sandbox Code Playgroud)

为了使这个可以立即重用,让我们把它放在一个函数中.

function deduplicate(data) {
    if (data.length > 0) {
        var result = [];

        data.forEach(function (elem) {
            if (result.indexOf(elem) === -1) {
                result.push(elem);
            }
        });

        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,为了摆脱重复,我们现在就这样做.

var uniqueCars = deduplicate(cars);
Run Code Online (Sandbox Code Playgroud)

当函数完成时,该deduplicate(cars)部分成为我们命名结果的东西.

只需传递你喜欢的任何数组的名称.


Fre*_*888 24

原始值

Set(推荐)

var array = ["FreePhoenix888", "FreePhoenix888", "konard", "FreePhoenix888"];

let set = [...new Set(array)];

console.log(set); // ["FreePhoenix888", "konard"]
Run Code Online (Sandbox Code Playgroud)

没有Set

function filterUniqueObjects(value, index, array) {
  return array.indexOf(value) === index;
}

// usage example:
var array = ["FreePhoenix888", "FreePhoenix888", "konard", "FreePhoenix888"];
var arrayOfUniqueItems = array.filter(filterUniqueObjects);

console.log(arrayOfUniqueItems); // ["FreePhoenix888", "konard"]
Run Code Online (Sandbox Code Playgroud)

对象

此示例展示了如何不仅过滤原始值数组,还过滤对象数组。我添加了注释,以便您更轻松地了解可以根据您的要求进行更改的内容。

let array = [
  { name: '@deep-foundation/core', version: '0.0.2' },
  { name: '@deep-foundation/capacitor-device', version: '10.0.1' },
  { name: '@deep-foundation/capacitor-device', version: '10.0.2' },
];

// Of course you can inline this function as filter argument uniqueArray.filter((item, index, self) => self.findIndex(innerItem => innerItem.name === item.name) === index);
function filterUniqueObjects(value, index, self) {
  return (
    self.findIndex(
      // Modify this function as you desire. You may want to calculate uniqueness depending only on specific fields, not all
      (obj) => obj.name === value.name
    ) === index
  );
};

let uniqueArray = array
  .reverse() // If you want latest duplicates to remain
  .filter(filterUniqueObjects)
  .reverse(); // To get back to original order after first reverse

console.log(uniqueArray)
Run Code Online (Sandbox Code Playgroud)


Gia*_*dei 22

您可以简单地使用内置函数Array.prototype.filter()Array.prototype.indexOf()

array.filter((x, y) => array.indexOf(x) == y)

var arr = [1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 6, 9];

var newarr = arr.filter((x, y) => arr.indexOf(x) == y);

console.log(newarr);
Run Code Online (Sandbox Code Playgroud)


ser*_*eyz 20

["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);
Run Code Online (Sandbox Code Playgroud)


小智 17

这个原型getUnique并不完全正确,因为如果我有一个类似的数组:["1",1,2,3,4,1,"foo"]它将返回["1","2","3","4"]并且"1"是字符串并且1是一个整数; 它们是不同的.

这是一个正确的解决方案:

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });
Run Code Online (Sandbox Code Playgroud)

使用:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();
Run Code Online (Sandbox Code Playgroud)

以上将产生["1",2,3,4,1,"foo"].

  • @Rob正是我所说的,PHP人们会认为`$ foo`是在javascript中声明变量的方式,而实际上是'var foo`. (8认同)
  • 请注意,`$foo = 'bar'` 是 PHP 声明变量的方式。它将在 javascript 中工作,但会创建一个隐式全局,通常不应该这样做。 (2认同)

小智 17

我们可以使用ES6集来做到这一点:

var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));

console.log(uniqueArray);
Run Code Online (Sandbox Code Playgroud)

//输出将是

uniqueArray = [1,2,3,4,5];
Run Code Online (Sandbox Code Playgroud)


vsy*_*ync 16

在查看了这里的所有90 多个答案后,我发现还有一个空间:

Array.includes有一个非常方便的第二个参数:"fromIndex",所以通过使用它,filter回调方法的每次迭代都会搜索array,从[current index] + 1它开始保证不包括当前过滤的项目在查找中,也节省了时间。

//                               
var list = [0,1,2,2,3,'a','b',4,5,2,'a']

console.log( 
  list.filter((v,i) => !list.includes(v,i+1))
)

// [0,1,3,"b",4,5,2,"a"]
Run Code Online (Sandbox Code Playgroud)

解释:

例如,让我们假设filter函数当前在 index 处迭代2) 并且该索引处的值恰好是2。然后扫描重复项(includes方法)的数组部分是索引 2 ( )之后的所有内容i+1

                               
[0, 1, 2,   2 ,3 ,'a', 'b', 4, 5, 2, 'a']
          |---------------------------|
Run Code Online (Sandbox Code Playgroud)

并且由于当前过滤的项目的值2包含在数组的其余部分中,它将被过滤掉,因为前导感叹号否定过滤规则。


Kam*_*ski 14

魔法

a.filter(e=>!(t[e]=e in t)) 
Run Code Online (Sandbox Code Playgroud)

O(n) 表现 ; 我们假设您的阵列在a.这里的解释(+ Jeppe改进)

let t={}, unique= a=> a.filter(e=>!(t[e]=e in t));

// "stand-alone" version working with global t:
// a1.filter((t={},e=>!(t[e]=e in t)));

// Test data
let a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
let a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
let a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];

// Results
console.log(JSON.stringify( unique(a1) ))
console.log(JSON.stringify( unique(a2) ))
console.log(JSON.stringify( unique(a3) ))
Run Code Online (Sandbox Code Playgroud)

  • 这看起来非常酷,没有一个可靠的解释,我摔倒你,当我运行这个时,我会用比特币 (13认同)
  • 我的意思是你应该用一些解释来扩展你的答案,并评论它的解构.不要指望人们会找到这样有用的答案.(虽然看起来很酷但可能有效) (3认同)
  • 不是魔法,但很像“Set”答案,在字典中使用 O(1) 键查找。您是否需要增加计数器?“e=&gt;!(t[e]=e in t)”怎么样?不过,很好的答案。 (2认同)
  • @Jeppe当我运行你的改进时,我体验到[啊哈效果](https://en.wikipedia.org/wiki/Eureka_effect)(在我不知道我可以在除`之外的其他构造之外使用`in`运算符之前for`循环:P)-谢谢-我很感激,并且会给你的其他好的答案+2。 (2认同)
  • 嗯,这个解决方案确实很棒,但是它仅适用于元组 下面的示例工作不正确: `unique(['2', 2]) // ['2'];` `unique([[1, 7] , [1, '7'], ['1', 7], ['1', '7']]) // [1, 7]` 所以要小心使用这个 (2认同)

Cœu*_*œur 12

如果没有扩展Array.prototype(它被认为是一种不好的做法)或者使用jquery/underscore,你可以简单地filter使用数组.

保留最后一次:

    function arrayLastUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps last occurrence
            return c.indexOf(a, b + 1) < 0;
        });
    },
Run Code Online (Sandbox Code Playgroud)

或第一次出现:

    function arrayFirstUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps first occurrence
            return c.indexOf(a) === b;
        });
    },
Run Code Online (Sandbox Code Playgroud)

嗯,这是只有JavaScript的ECMAScript 5 +,这意味着只有IE9 +,但它很高兴在本地HTML开发/ JS(Windows应用商店的应用程序,火狐OS,煎茶,的PhoneGap,钛,...).

  • 事实上它是js 1.6并不意味着你不能使用`filter`.在[MDN页面](https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Array/filter),他们有一个Internet Explorer的实现,我的意思是,旧的浏览器.另外:JS 1.6仅指Firefox的js引擎,但正确的说它是ECMAScript 5. (2认同)

Dav*_*ave 12

这已经得到了很多回答,但它没有解决我的特殊需求。

很多答案都是这样的:

a.filter((item, pos, self) => self.indexOf(item) === pos);
Run Code Online (Sandbox Code Playgroud)

但这不适用于复杂对象的数组。

假设我们有一个这样的数组:

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];
Run Code Online (Sandbox Code Playgroud)

如果我们想要具有唯一名称的对象,我们应该使用array.prototype.findIndex代替array.prototype.indexOf

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);
Run Code Online (Sandbox Code Playgroud)


Dec*_*bal 11

如果您正在使用Prototype框架,则无需执行'for'循环,您可以使用http://www.prototypejs.org/api/array/uniq,如下所示:

var a = Array.uniq();  
Run Code Online (Sandbox Code Playgroud)

这将产生一个没有重复的重复数组.我遇到了一个问题,搜索一个方法来计算不同的数组记录

uniq的()

我用了

尺寸()

这是我的简单结果.ps对不起,如果我错误的输入了什么

编辑:如果要转义未定义的记录,可能需要添加

紧凑()

之前,像这样:

var a = Array.compact().uniq();  
Run Code Online (Sandbox Code Playgroud)

  • 因为我找到了一个更好的答案,我认为所有人的主题不仅仅是针对那个问题的人 (14认同)
  • 感谢时间机器,但 iirc 大约 15 年前,JS 社区进行了辩论,结果是 - 不要扩展原型,因为它会产生副作用,并导致你以这种方式污染所有 JS 数组。 (2认同)

Sum*_*tra 11

[...new Set(duplicates)]
Run Code Online (Sandbox Code Playgroud)

这是最简单的方法,并从MDN Web Docs中引用。

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
Run Code Online (Sandbox Code Playgroud)


Luc*_*eis 10

那是因为0JavaScript中的虚假价值.

this[i] 如果数组的值为0或任何其他假值,则将是假的.


eph*_*ent 10

Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}
Run Code Online (Sandbox Code Playgroud)


Suk*_*ala 10

最简单的答案是:

const array = [1, 1, 2, 2, 3, 5, 5, 2];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 5]
Run Code Online (Sandbox Code Playgroud)

  • 很简单,但它不适用于对象数组。 (2认同)

shu*_*111 9

我有一个稍微不同的问题,我需要从数组中删除具有重复id属性的对象。这工作。

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);
Run Code Online (Sandbox Code Playgroud)


Kri*_* PC 9

现在,您可以使用集合删除重复项并将其转换回数组。

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];

console.log([...new Set(names)])
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是使用排序和过滤

var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
var namesSorted = names.sort();
const result = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);
console.log(result);
Run Code Online (Sandbox Code Playgroud)


MUH*_*MAN 9

在 ES6/更高版本中

只获取唯一值

  let a = [
           { id: 1, name: "usman" },
           { id: 2, name: "zia" },
           { id: 3, name: "usman" },
          ];
const unique = [...new Set(a.map((item) => item.name))];
console.log(unique); // ["usman", "zia"]
Run Code Online (Sandbox Code Playgroud)

获取独特的对象

const myObjArray = [
                       { id: 1, name: "usman" },
                       { id: 2, name: "zia" },
                       { id: 3, name: "usman" },
                   ];
// Creates an array of objects with unique "name" property values.
let uniqueObjArray = [
  ...new Map(myObjArray.map((item) => [item["name"], item])).values(),
];

console.log("uniqueObjArray", uniqueObjArray);
Run Code Online (Sandbox Code Playgroud)


小智 8

如果您可以接受额外的依赖项,或者您的代码库中已经有一个库,您可以使用 LoDash(或 Underscore)从数组中删除重复项。

用法

如果您的代码库中还没有它,请使用 npm 安装它:

npm install lodash
Run Code Online (Sandbox Code Playgroud)

然后按如下方式使用它:

import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);
Run Code Online (Sandbox Code Playgroud)

出去:

[ 1, 2, 3 ]
Run Code Online (Sandbox Code Playgroud)


akh*_*hid 7

基于ES6的解决方案...

var arr = [2, 3, 4, 2, 3, 4, 2];
const result = [...new Set(arr)];
console.log(result);
Run Code Online (Sandbox Code Playgroud)


Fro*_*y Z 6

来自Shamasis Bhattacharya的博客(O(2n)时间复杂度):

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};
Run Code Online (Sandbox Code Playgroud)

来自Paul Irish的博客:改进JQuery .unique():

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)


小智 6

我不确定为什么加布里埃尔·西尔维拉(Gabriel Silveira)用这种方式编写函数,但是一个更简单的形式对我来说也是如此,没有缩小是:

Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};
Run Code Online (Sandbox Code Playgroud)

或者在CoffeeScript中:

Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )
Run Code Online (Sandbox Code Playgroud)


Jas*_*son 6

看来我们已经失去了拉斐尔(Rafael)的答案,该答案已被接受为几年。如果您没有混合类型的数组,那么这(至少在2017年)是性能最佳的解决方案:

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}
Run Code Online (Sandbox Code Playgroud)

如果确实有混合类型的数组,则可以序列化哈希键:

Array.prototype.getUnique = function() {
    var hash = {}, result = [], key; 
    for ( var i = 0, l = this.length; i < l; ++i ) {
        key = JSON.stringify(this[i]);
        if ( !hash.hasOwnProperty(key) ) {
            hash[key] = true;
            result.push(this[i]);
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)


Sar*_*man 6

以简单的方法查找唯一的Array值

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]
Run Code Online (Sandbox Code Playgroud)


Le *_*oid 5

为了解决这个问题,在加载数组时没有重复可能是有用的,Set对象会这样做,但它还没有在所有浏览器中都可用.如果您需要多次查看其内容,它可以节省内存并提高效率.

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}
Run Code Online (Sandbox Code Playgroud)

样品:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });
Run Code Online (Sandbox Code Playgroud)

给你 set = [1,3,4,2]


dav*_*tar 5

奇怪的是之前没有建议..要删除id数组中对象键(下面)的重复项,你可以这样做:

const uniqArray = array.filter((obj, idx, arr) => (
  arr.findIndex((o) => o.id === obj.id) === idx
)) 
Run Code Online (Sandbox Code Playgroud)


小智 5

对于具有一些唯一 id 的基于对象的数组,我有一个简单的解决方案,您可以通过它按线性复杂度排序

function getUniqueArr(arr){
    const mapObj = {};
    arr.forEach(a => { 
       mapObj[a.id] = a
    })
    return Object.values(mapObj);
}
Run Code Online (Sandbox Code Playgroud)


Rom*_*man 5

任务是从由任意类型(原始和非原始)组成的数组中获取唯一数组。

基于使用的new Set(...)方法并不新鲜。在这里,它由JSON.stringify(...),JSON.parse(...)[].map方法利用。优点是通用性(适用于任何类型的数组)、简短的 ES6 符号以及这种情况下可能的性能

const dedupExample = [
    { a: 1 },
    { a: 1 },
    [ 1, 2 ],
    [ 1, 2 ],
    1,
    1,
    '1',
    '1'
]

const getUniqArrDeep = arr => {
    const arrStr = arr.map(item => JSON.stringify(item))
    return [...new Set(arrStr)]
        .map(item => JSON.parse(item))
}

console.info(getUniqArrDeep(dedupExample))
   /* [ {a: 1}, [1, 2], 1, '1' ] */
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

1224417 次

最近记录:

5 年,9 月 前