繁体   English   中英

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

[英]Get all unique values in a JavaScript array (remove duplicates)

我有一组数字,我需要确保它们是唯一的。 我在 inte.net 上找到了下面的代码片段,它工作得很好,直到数组中有一个零。 我在 Stack Overflow 上发现了这个其他脚本,它看起来几乎与它一模一样,但它并没有失败。

所以为了帮助我学习,谁能帮我确定原型脚本哪里出错了?

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;
}

重复问题的更多答案:

类似问题:

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

 function onlyUnique(value, index, self) { return self.indexOf(value) === index; } // usage example: var a = ['a', 1, 'a', 2, '1']; var unique = a.filter(onlyUnique); console.log(unique); // ['a', 1, 2, '1']

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

onlyUnique检查给定值是否是第一个出现的值。 如果不是,它必须是重复的,不会被复制。

此解决方案无需任何额外的库(如 jQuery 或原型.js)即可工作。

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

对于不支持原生方法filterindexOf的旧浏览器 (<ie9),您可以在 MDN 文档中找到filterindexOf的变通方法。

如果要保留最后一次出现的值,只需将indexOf替换为lastIndexOf

使用 ES6,这可以缩短为:

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

感谢Camilo Martin的评论提示。

ES6 有一个原生对象Set来存储唯一值。 要获取具有唯一值的数组,您现在可以这样做:

 var myArray = ['a', 1, 'a', 2, '1']; let unique = [...new Set(myArray)]; console.log(unique); // unique is ['a', 1, 2, '1']

Set的构造函数接受一个可迭代的对象,比如一个数组,而扩展运算符...将集合转换回一个数组。 感谢Lukas Liese的评论提示。

更新了 ES6/ES2015 的答案:使用Set扩展运算符(感谢le-m ),单行解决方案是:

let uniqueItems = [...new Set(items)]

哪个返回

[4, 5, 6, 3, 2, 23, 1]

我将所有答案拆分为 4 种可能的解决方案:

  1. 使用 object { }防止重复
  2. 使用辅助数组[ ]
  3. 使用filter + indexOf
  4. 奖金! ES6 Sets方法。

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

使用 object { }防止重复

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

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

  return Object.keys(j).map(function(v){
    return j[v];
  });
} 

使用辅助数组[ ]

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;
}

使用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;
}

使用ES6 [...new Set(a)]

function uniqueArray4(a) {
  return [...new Set(a)];
}

我想知道哪个更快。 我制作了示例 Google Sheet来测试功能。 注意:ECMA 6 在 Google 表格中不可用,因此我无法对其进行测试。

以下是测试结果: 在此处输入图像描述

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

2020 年更新

Google Script 启用了 ES6 引擎。 现在我用Sets测试了最后一个代码,它看起来比对象方法更快。

您也可以使用underscore.js

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

这将返回:

[1, 2, 3, 4]

一个班轮,纯 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")

在此处输入图像描述

使用 ES5 语法

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

浏览器兼容性:IE9+

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

在现代浏览器中,一个干净简单的解决方案是将数据存储在一个Set中,它被设计为一个唯一值的列表。

 const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford']; const uniqueCars = Array.from(new Set(cars)); console.log(uniqueCars);

Array.from对于将 Set 转换回数组很有用,这样您就可以轻松访问数组拥有的所有很棒的方法(功能)。 还有其他方法可以做同样的事情。 但是你可能根本不需要Array.from ,因为 Set 有很多有用的特性,比如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);
    }
});

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

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

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

        return result;
    }
}

所以为了摆脱重复,我们现在就这样做。

var uniqueCars = deduplicate(cars);

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

只需将您喜欢的任何数组的名称传递给它。

使用 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]

使用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]

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

或者,如果您想修改 Array 原型(如原始问题):

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};

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

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

学习 ES6 的资源:

从那以后,我发现了一个使用 jQuery 的好方法

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});

注意:此代码是从Paul Irish 的打鸭帖中提取的 - 我忘了注明:P

最简单的解决方案:

 var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1]; console.log([...new Set(arr)]);

要么:

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

使用Set删除重复项。

// Array with duplicates⤵️
const withDuplicates = [2, 2, 5, 5, 1, 1, 2, 2, 3, 3];
// Get new array without duplicates by using Set
// [2, 5, 1, 3]
const withoutDuplicates = Array.from(new Set(arrayWithDuplicates));

一个较短的版本,如下:

const withoutDuplicates = [...new Set(arrayWithDuplicates)];

执行此操作的最简单、最快(在 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;
}

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

根据 JSBench 的说法,这个功能是我在任何地方都能找到的最快的功能——尽管您可以随意添加自己的功能。

非原型版本:

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;
}

排序

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

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;
}

或非原型:

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;
}

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

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

如果您不需要重用旧数组;顺便说一句,在将其转换为 unique 之前执行必要的其他操作可能是最快的方法,也很短。

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

那么你可以试试这个

 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]

我想出了这个功能阅读这篇文章...

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

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

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

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

在这一点上,我正在考虑我在我的独特功能中真正需要什么。 我不需要旧数组,我想要一个快速的功能。 所以我用了2个while循环+拼接。 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})请使用Object.defineProperty(Array.prototype,...,writable:false,enumerable:false})https : //stackoverflow.com/a/20463021/2450730

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

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

如果你看不懂上面的代码,请阅读一本 javascript 书籍,或者这里有一些关于较短代码的解释。 https://stackoverflow.com/a/21353032/2450730

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

对于空数组

!array.length||toUnique(array); 

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

 var duplicatesArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4]; var uniqueArray = [...new Set(duplicatesArray)]; console.log(uniqueArray); // [1,2,3,4,5]

魔法

a.filter(e=>!(t[e]=e in t)) 

O(n)性能(比new Set快); 我们假设您的数组位于at={}中。 此处说明(+ Jeppe展示次数)

 let t, unique= a=> ( t={}, 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) ))

["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;
 }, []);

这个原型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 });

使用:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

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

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

Array.includes有一个非常方便的第二个参数: “fromIndex” ,因此通过使用它, filter回调方法的每次迭代都会搜索数组,从 [当前[current index] + 1开始,这保证不会在查找并节省时间。

注意 - 此解决方案不保留顺序,因为它从左到右删除了重复的项目,但如果ArrayObjects的集合,它将赢得Set技巧。

 // 🚩 🚩 🚩 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"]

解释:

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

           👇                    👇
[0, 1, 2,   2 ,3 ,'a', 'b', 4, 5, 2, 'a']
       👆   |---------------------------|

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


如果顺序很重要,请使用以下方法:

 // 🚩 🚩 🚩 var list = [0,1,2,2,3,'a','b',4,5,2,'a'] console.log( // Initialize with empty array and fill with non-duplicates list.reduce((acc, v) => (!acc.includes(v) && acc.push(v), acc), []) ) // [0,1,2,3,"a","b",4,5]

您可以简单地使用内置函数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);

[...new Set(duplicates)]

这是最简单的一种,引用自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]

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

很多答案是这样的:

a.filter((item, pos, self) => self.indexOf(item) === pos);

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

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

const a = [
 { age: 4, name: 'fluffy' },
 { age: 5, name: 'spot' },
 { age: 2, name: 'fluffy' },
 { age: 3, name: 'toby' },
];

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

a.filter((item, pos, self) => self.findIndex(v => v.name === item.name) === pos);

无需扩展 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;
        });
    },

或第一次出现:

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

好吧,它只是 javascript ECMAScript 5+,这意味着只有 IE9+,但它非常适合原生 HTML/JS(Windows Store App、Firefox OS、Sencha、Phonegap、Titanium 等)的开发。

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
}

那是因为0在 JavaScript 中是一个虚假值。

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

如果您使用的是 Prototype 框架,则无需执行“for”循环,您可以像这样使用http://prototypejs.org/doc/latest/language/Array/prototype/uniq/

var a = Array.uniq();  

这将产生一个没有重复的重复数组。 我遇到了您搜索计算不同数组记录的方法的问题,因此在uniq()之后我使用了size()并且得到了简单的结果。 ps对不起,如果我打错了什么

编辑:如果您想转义未定义的记录,您可能需要在之前添加compact() ,如下所示:

var a = Array.compact().uniq();  

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

 var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"]; console.log([...new Set(names)])

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

 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);

您可以使用 Set 运算符从数组中获取唯一值

 const uniqueArray = [...new Set([1, 1, 1])]; console.log(uniqueArray) // [1]

最简单的答案是:

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

我有一个稍微不同的问题,我需要从数组中删除具有重复 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);

如果您对额外的依赖项没有问题,或者您的代码库中已经有一个库,您可以使用 LoDash(或下划线)从适当的数组中删除重复项。

用法

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

npm install lodash

然后按如下方式使用它:

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

出去:

[ 1, 2, 3 ]

我不确定为什么 Gabriel Silveira 以这种方式编写函数,但一种更简单的形式也适用于我并且没有缩小:

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

或在 CoffeeScript 中:

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

看来我们已经失去了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;
}

如果你确实有一个混合类型的数组,你可以序列化散列键:

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;
}

以简单的方法查找唯一的数组值

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]

基于ES6的解决方案...

 var arr = [2, 3, 4, 2, 3, 4, 2]; const result = [...new Set(arr)]; console.log(result); 

来自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;
};

来自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]

奇怪的是,这之前没有被建议过..要通过数组中的对象键(下面的id )删除重复项,您可以执行以下操作:

const uniqArray = array.filter((obj, idx, arr) => (
  arr.findIndex((o) => o.id === obj.id) === idx
)) 

为了解决该问题,反之亦然,加载数组时不重复可能很有用, Set对象可以做到这一点,但并非所有浏览器都可用。 如果您需要多次查看其内容,它可以节省内存并提高效率。

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}

样品:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });

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

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

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

使用对象键制作唯一数组,我尝试过以下操作

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

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


  return Object.keys(j).map(function(v){
    return j[v];
  });
}   

uniqueArray(["1",1,2,3,4,1,"foo", false, false, null,1]);

返回["1", 1, 2, 3, 4, "foo", false, null]

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

基于使用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' ] */

如前所述, [...new Set(values)]是最好的选择,如果您可以使用的话。

否则,这是一个不会为每个索引迭代数组的单行代码:

values.sort().filter((val, index, arr) => index === 0 ? true : val !== arr[index - 1]);

这只是将每个值与其之前的值进行比较。 结果将被排序。

例子:

 let values = [ 1, 2, 3, 3, 4, 5, 5, 5, 4, 4, 4, 5, 1, 1, 1, 3, 3 ]; let unique = values.sort().filter((val, index, arr) => index === 0 ? true : val !== arr[index - 1]); console.log(unique);

如果有人使用knockoutjs

ko.utils.arrayGetDistinctValues()

顺便说一句,查看了所有ko.utils.array*实用程序。

在其他答案的基础上,这是另一个变体,它采用可选标志来选择策略(保持第一次出现或保持最后一次出现):

不扩展Array.prototype

function unique(arr, keepLast) {
  return arr.filter(function (value, index, array) {
    return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
  });
};

// Usage
unique(['a', 1, 2, '1', 1, 3, 2, 6]); // -> ['a', 1, 2, '1', 3, 6]
unique(['a', 1, 2, '1', 1, 3, 2, 6], true); // -> ['a', '1', 1, 3, 2, 6]

扩展Array.prototype

Array.prototype.unique = function (keepLast) {
  return this.filter(function (value, index, array) {
    return keepLast ? array.indexOf(value, index + 1) < 0 : array.indexOf(value) === index;
  });
};

// Usage
['a', 1, 2, '1', 1, 3, 2, 6].unique(); // -> ['a', 1, 2, '1', 3, 6]
['a', 1, 2, '1', 1, 3, 2, 6].unique(true); // -> ['a', '1', 1, 3, 2, 6]

使用 One Liner 在对象数组中查找唯一

const uniqueBy = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
// f -> should must return string because it will be use as key

const data = [
  { comment: "abc", forItem: 1, inModule: 1 },
  { comment: "abc", forItem: 1, inModule: 1 },
  { comment: "xyz", forItem: 1, inModule: 2 },
  { comment: "xyz", forItem: 1, inModule: 2 },
];

uniqueBy(data, (x) => x.forItem +'-'+ x.inModule); // find unique by item with module
// output
// [
//   { comment: "abc", forItem: 1, inModule: 1 },
//   { comment: "xyz", forItem: 1, inModule: 2 },
// ];

// can also use for strings and number or other primitive values

uniqueBy([1, 2, 2, 1], (v) => v); // [1, 2]
uniqueBy(["a", "b", "a"], (v) => v); // ['a', 'b']

uniqueBy(
  [
    { id: 1, name: "abc" },
    { id: 2, name: "xyz" },
    { id: 1, name: "abc" },
  ],
  (v) => v.id
);
// output
// [
//   { id: 1, name: "abc" },
//   { id: 2, name: "xyz" },
// ];

你也可以使用 jQuery

var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4];

// note: jQuery's filter params are opposite of javascript's native implementation :(
var unique = $.makeArray($(a).filter(function(i,itm){ 
    // note: 'index', not 'indexOf'
    return i == $(a).index(itm);
}));

// unique: [1, 5, 6, 4, 2, 3]

最初回答于: jQuery 函数从数组中获取所有唯一元素?

看这个。 jquery提供uniq方法: https ://api.jquery.com/jQuery.unique/

var ids_array = []

$.each($(my_elements), function(index, el) {
    var id = $(this).attr("id")
    ids_array.push(id)
});

var clean_ids_array = jQuery.unique(ids_array)

$.each(clean_ids_array, function(index, id) {
   elment = $("#" + id)   // my uniq element
   // TODO WITH MY ELEMENT
});

使用lodash和 identity lambda 函数,只需在使用对象之前定义它

const _ = require('lodash');
...    
_.uniqBy([{a:1,b:2},{a:1,b:2},{a:1,b:3}], v=>v.a.toString()+v.b.toString())
_.uniq([1,2,3,3,'a','a','x'])

并将拥有:

[{a:1,b:2},{a:1,b:3}]
[1,2,3,'a','x']

(这是最简单的方法)

重复数据删除通常需要给定类型的相等运算符。 但是,使用eq函数会阻止我们使用Set以有效的方式确定重复项,因为Set回退到=== 正如您肯定知道的那样, ===不适用于引用类型。 所以如果卡住了,我们很友善,对吧?

出路是简单地使用一个转换器函数,它允许我们将(引用)类型转换为我们可以使用Set实际查找的东西。 例如,我们可以使用散列函数,或者JSON.stringify数据结构,如果它不包含任何函数。

通常我们只需要访问一个属性,然后我们可以比较它而不是Object的引用。

这里有两个满足这些要求的组合器:

 const dedupeOn = k => xs => { const s = new Set(); return xs.filter(o => s.has(o[k]) ? null : (s.add(o[k]), o[k])); }; const dedupeBy = f => xs => { const s = new Set(); return xs.filter(x => { const r = f(x); return s.has(r) ? null : (s.add(r), x); }); }; const xs = [{foo: "a"}, {foo: "b"}, {foo: "A"}, {foo: "b"}, {foo: "c"}]; console.log( dedupeOn("foo") (xs)); // [{foo: "a"}, {foo: "b"}, {foo: "A"}, {foo: "c"}] console.log( dedupeBy(o => o.foo.toLowerCase()) (xs)); // [{foo: "a"}, {foo: "b"}, {foo: "c"}]

使用这些组合器,我们可以非常灵活地处理各种重复数据删除问题。 这不是最快的方法,而是最具表现力和最通用的方法。

这是一个几乎是 O(n) 的单行代码,保留第一个元素,并且您可以将唯一的字段分开。

这是函数式编程中非常常见的技术 - 您使用reduce来构建您返回的数组。 由于我们像这样构建数组,我们保证我们得到一个稳定的排序,这与[...new Set(array)]方法不同。 我们仍然使用Set来确保我们没有重复,因此我们的累加器包含Set和我们正在构建的数组。

 const removeDuplicates = (arr) => arr.reduce( ([set, acc], item) => set.has(item) ? [set, acc] : [set.add(item), (acc.push(item), acc)], [new Set(), []] )[1]

以上内容适用于简单值,但不适用于对象,类似于[...new Set(array)]的分解方式。 如果项目是包含id属性的对象,你会这样做:

 const removeDuplicates = (arr) => arr.reduce( ([set, acc], item) => set.has(item.id) ? [set, acc] : [set.add(item.id), (acc.push(item), acc)], [new Set(), []] )[1]

要删除重复项,可能有两种情况。 首先,所有的数据都不是对象,其次,所有的数据都是对象。

如果所有数据都是任何类型的原始数据类型,例如 int、float、string 等,那么您可以按照这个

const uniqueArray = [...new Set(oldArray)]

但是假设您的数组包含如下 JS 对象

{
    id: 1,
    name: 'rony',
    email: 'rony@example.com'
}

然后要获取您可以遵循的所有独特对象

let uniqueIds = [];
const uniqueUsers = oldArray.filter(item => {
    if(uniqueIds.includes(item.id)){
        return false;
    }else{
        uniqueIds.push(item.id);
        return true;
    }
})

您还可以使用此方法制作任何类型的数组以使其独一无二。 只需将跟踪键保留在uniqueIds数组中即可。

 let ar = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 2, 1]; let unique = ar.filter((value, index) => { return ar.indexOf(value) == index; }); console.log(unique);

您可以使用 Set 来消除重复项。

const originalNumbers = [1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 1, 2, 9];
const uniqueNumbersSet = new Set(originalNumbers);

/** get the array back from the set */
const uniqueNumbersArray = Array.from(uniqueNumbersSet);

/** uniqueNumbersArray outputs to: [1, 2, 3, 4, 5, 9] */

了解有关设置的更多信息: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

一个简单的代码如下:

let arr = [1,'k',12,1,1,'k','12'];
let distictArr=arr.filter((item, index, arr) => arr.indexOf(item) === index);

console.log(distictArr); // [1, 'k', 12, '12']

你也可以使用sugar.js:

[1,2,2,3,1].unique() // => [1,2,3]

[{id:5, name:"Jay"}, {id:6, name:"Jay"}, {id: 5, name:"Jay"}].unique('id') 
  // => [{id:5, name:"Jay"}, {id:6, name:"Jay"}]

桩的另一种解决方案。

我最近需要制作一个唯一的排序列表,我使用过滤器来跟踪对象中的前一个项目,如下所示:

uniqueArray = sortedArray.filter(function(e) { 
    if(e==this.last) 
      return false; 
    this.last=e; return true;  
  },{last:null});

接受选择器的版本应该非常快速和简洁:

function unique(xs, f) {
  var seen = {};
  return xs.filter(function(x) {
    var fx = (f && f(x)) || x;
    return !seen[fx] && (seen[fx] = 1);
  });
}

这个不纯,会修改数组,但是这个是最快的。 如果您的速度更快,请在评论中写下;)

http://jsperf.com/unique-array-webdeb

Array.prototype.uniq = function(){
    for(var i = 0, l = this.length; i < l; ++i){
        var item = this[i];
        var duplicateIdx = this.indexOf(item, i + 1);
        while(duplicateIdx != -1) {
            this.splice(duplicateIdx, 1);
            duplicateIdx = this.indexOf(item, duplicateIdx);
            l--;
        }
    }

    return this;
}

[
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc",
 "",2,4,"A","abc"
].uniq() //  ["",2,4,"A","abc"]
var a = [1,4,2,7,1,5,9,2,4,7,2]
var b = {}, c = {};
var len = a.length;
for(var i=0;i<len;i++){
  a[i] in c ? delete b[a[i]] : b[a[i]] = true;
  c[a[i]] = true;
} 

// b contains all unique elements

对于字符串数组:

function removeDuplicatesFromArray(arr) {
  const unique = {};
  arr.forEach((word) => {
    unique[word] = 1; // it doesn't really matter what goes here
  });
  return Object.keys(unique);
}

您可以使用Ramda.js ,一个功能性的 JavaScript 库来执行此操作:

 var unique = R.uniq([1, 2, 1, 3, 1, 4]) console.log(unique)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

很多人已经提到使用...

[...new Set(arr)];

这是一个很好的解决方案,但我更喜欢与.filter一起使用的解决方案。 在我看来,过滤器是一种更自然的方式来获得独特的价值。 您正在有效地删除重复项,而从数组中删除元素正是过滤器的目的。 它还允许您链接.map.reduce和其他.filter调用。 我设计了这个解决方案......

const unique = () => {
  let cache;  
  return (elem, index, array) => {
    if (!cache) cache = new Set(array);
    return cache.delete(elem);
  };
};

myArray.filter(unique());

需要注意的是,您需要关闭,但我认为这是一个值得权衡的选择。 在性能方面,它比我看到的其他使用.filter的解决方案性能更高,但性能比[...new Set(arr)]差。

另请参阅我的 github 包youneek

如果您只想获取唯一元素并删除重复一次的元素,您可以这样做:

 let array = [2, 3, 4, 1, 2, 8, 1, 1, 2, 9, 3, 5, 3, 4, 8, 4]; function removeDuplicates(inputArray) { let output = []; let countObject = {}; for (value of array) { countObject[value] = (countObject[value] || 0) + 1; } for (key in countObject) { if (countObject[key] === 1) { output.push(key); } } return output; } console.log(removeDuplicates(array));

你根本不需要 .indexOf() ; 你可以这样做 O(n):

function SelectDistinct(array) {
    const seenIt = new Set();

    return array.filter(function (val) {
        if (seenIt.has(val)) { 
            return false;
        }

        seenIt.add(val);

        return true;
    });
}

var hasDuplicates = [1,2,3,4,5,5,6,7,7];
console.log(SelectDistinct(hasDuplicates)) //[1,2,3,4,5,6,7]

如果您不想使用 .filter():

function SelectDistinct(array) {
    const seenIt = new Set();
    const distinct = [];

    for (let i = 0; i < array.length; i++) {
        const value = array[i];

        if (!seenIt.has(value)) {
            seenIt.add(value);
            distinct.push(value);
        }
    }
    
    return distinct; 
    /* you could also drop the 'distinct' array and return 'Array.from(seenIt)', which converts the set object to an array */
}

在我的解决方案中,我在过滤之前对数据进行排序:

const uniqSortedArray = dataArray.sort().filter((v, idx, t) => idx==0 || v != t[idx-1]); 

 var myArray = ["a",2, "a", 2, "b", "1"]; const uniques = []; myArray.forEach((t) => !uniques.includes(t) && uniques.push(t)); console.log(uniques);

如果你想删除重复项,返回整个对象并想使用 ES6 Set 和 Map 语法,并且只运行一个循环,你可以试试这个,以获得唯一的 id:

 const collection = [{id:3, name: "A"}, {id:3, name: "B"}, {id:4, name: "C"}, {id:5, name: "D"}] function returnUnique(itemsCollection){ const itemsMap = new Map(); itemsCollection.forEach(item => { if(itemsMap.size === 0){ itemsMap.set(item.id, item) }else if(!itemsMap.has(item.id)){ itemsMap.set(item.id, item) } }); return [...new Set(itemsMap.values())]; } console.log(returnUnique(collection));

并不是对原始问题的直接字面回答,因为我更喜欢一开始就不在数组中包含重复值。 所以这是我的UniqueArray

class UniqueArray extends Array {
    constructor(...args) {
        super(...new Set(args));
    }
    push(...args) {
        for (const a of args) if (!this.includes(a)) super.push(a);
        return this.length;
    }
    unshift(...args) {
        for (const a of args.reverse()) if (!this.includes(a)) super.unshift(a);
        return this.length;
    }
    concat(...args) {
        var r = new UniqueArray(...this);
        for (const a of args) r.push(...a);
        return r;
    }
}
> a = new UniqueArray(1,2,3,1,2,4,5,1)
UniqueArray(5) [ 1, 2, 3, 4, 5 ]
> a.push(1,4,6)
6
> a
UniqueArray(6) [ 1, 2, 3, 4, 5, 6 ]
> a.unshift(1)
6
> a
UniqueArray(6) [ 1, 2, 3, 4, 5, 6 ]
> a.unshift(0)
7
> a
UniqueArray(7) [
  0, 1, 2, 3,
  4, 5, 6
]
> a.concat(2,3,7)
UniqueArray(8) [
  0, 1, 2, 3,
  4, 5, 6, 7
]

已经有很多很棒的答案了。 这是我的方法。

var removeDuplicates = function(nums) {
    let filteredArr = [];
    nums.forEach((item) => {
        if(!filteredArr.includes(item)) {
            filteredArr.push(item);
        }
    })

  return filteredArr;
}

对于元组数组,我将把东西放入 Map 并让它完成工作。 使用这种方法,您必须注意要使用的密钥:

const arrayOfArraysWithDuplicates = [
    [1, 'AB'],
    [2, 'CD'],
    [3, 'EF'],
    [1, 'AB'],
    [2, 'CD'],
    [3, 'EF'],
    [3, 'GH'],
]

const uniqueByFirstValue = new Map();
const uniqueBySecondValue = new Map();

arrayOfArraysWithDuplicates.forEach((item) => {
    uniqueByFirstValue.set(item[0], item[1]);
    uniqueBySecondValue.set(item[1], item[0]);
});

let uniqueList = Array.from( uniqueByFirstValue, ( [ value, name ] ) => ( [value, name] ) );

console.log('Unique by first value:');
console.log(uniqueList);

uniqueList = Array.from( uniqueBySecondValue, ( [ value, name ] ) => ( [value, name] ) );

console.log('Unique by second value:');
console.log(uniqueList);

输出:

Unique by first value:
[ [ 1, 'AB' ], [ 2, 'CD' ], [ 3, 'GH' ] ]

Unique by second value:
[ [ 'AB', 1 ], [ 'CD', 2 ], [ 'EF', 3 ], [ 'GH', 3 ] ]

在 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"]

获取独特的对象

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);

如果顺序不重要,那么我们可以进行哈希并获取键以创建唯一数组。

var ar = [1,3,4,5,5,6,5,6,2,1];
var uarEle = {};
links.forEach(function(a){ uarEle[a] = 1; });
var uar = keys(uarEle)

uar 将具有唯一的数组元素。

我在 jsperf 上查看了 Joeytje50 的代码,他比较了许多替代方案。 他的代码有许多小错别字,这对性能和正确性产生了影响。

更重要的是,他正在一个非常小的阵列上进行测试。 我制作了一个包含 1000 个整数的数组。 每个整数是 0 到 1000 之间的随机整数的 100 倍。这使得平均大约 1000/e = 368 个重复。 结果在jsperf

这是可能需要效率的更现实的场景。 这些变化使声明发生了巨大的变化(特别是被吹捧为最快的代码远不及快速)。 明显的赢家是使用散列技术的地方,最好的是

Array.prototype.getUnique3 = function(){
   var u = Object.create(null), a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(this[i] in u) continue;
      a.push(this[i]);
      u[this[i]] = 1;
   }
   return a.length;
}

我知道这已经被回答到死了......但是......没有人提到过 linq 的 javascript 实现。 然后可以使用.distinct()方法 - 它使代码超级容易阅读。

var Linq = require('linq-es2015');
var distinctValues =  Linq.asEnumerable(testValues)
            .Select(x)
            .distinct()
            .toArray();

 var testValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1]; var distinctValues = Enumerable.asEnumerable(testValues) .distinct() .toArray(); console.log(distinctValues);
 <script src="https://npmcdn.com/linq-es5/dist/linq.js"></script>

如果你有一个对象数组,并且你想要一个uniqueBy函数,比如说,通过一个 id 字段:

function uniqueBy(field, arr) {
   return arr.reduce((acc, curr) => {
     const exists = acc.find(v => v[field] === curr[field]);
     return exists ? acc : acc.concat(curr);
   }, [])
}

使用 field[2] 作为 Id 创建一个唯一数组的数组:

 const arr = [ ['497', 'Q0', 'WTX091-B06-138', '0', '1.000000000', 'GROUP001'], ['497', 'Q0', 'WTX091-B09-92', '1', '0.866899288', 'GROUP001'], ['497', 'Q0', 'WTX091-B09-92', '2', '0.846036819', 'GROUP001'], ['497', 'Q0', 'WTX091-B09-57', '3', '0.835025326', 'GROUP001'], ['497', 'Q0', 'WTX091-B43-79', '4', '0.765068215', 'GROUP001'], ['497', 'Q0', 'WTX091-B43-56', '5', '0.764211464', 'GROUP001'], ['497', 'Q0', 'WTX091-B44-448', '6', '0.761701704', 'GROUP001'], ['497', 'Q0', 'WTX091-B44-12', '7', '0.761701704', 'GROUP001'], ['497', 'Q0', 'WTX091-B49-128', '8', '0.747434800', 'GROUP001'], ['497', 'Q0', 'WTX091-B18-17', '9', '0.746724770', 'GROUP001'], ['497', 'Q0', 'WTX091-B19-374', '10', '0.733379549', 'GROUP001'], ['497', 'Q0', 'WTX091-B19-344', '11', '0.731421782', 'GROUP001'], ['497', 'Q0', 'WTX091-B09-92', '12', '0.726450470', 'GROUP001'], ['497', 'Q0', 'WTX091-B19-174', '13', '0.712757036', 'GROUP001'] ]; arr.filter((val1, idx1, arr) => !!~val1.indexOf(val1[2]) && !(arr.filter((val2, idx2) => !!~val2.indexOf(val1[2]) && idx2 < idx1).length)); console.log(arr);

这是一个 ES6 函数,它从对象数组中删除重复项,通过指定的对象属性进行过滤

function dedupe(arr = [], fnCheck = _ => _) {
  const set = new Set();
  let len = arr.length;

  for (let i = 0; i < len; i++) {
    const primitive = fnCheck(arr[i]);
    if (set.has(primitive)) {
      // duplicate, cut it
      arr.splice(i, 1);
      i--;
      len--;
    } else {
      // new item, add it
      set.add(primitive);
    }
  }

  return arr;
}

const test = [
    {video:{slug: "a"}},
    {video:{slug: "a"}},
    {video:{slug: "b"}},
    {video:{slug: "c"}},
    {video:{slug: "c"}}
]
console.log(dedupe(test, x => x.video.slug));

// [{video:{slug: "a"}}, {video:{slug: "b"}}, {video:{slug: "c"}}]

我有一个解决方案,它使用 es6 reduce 并找到数组辅助方法来删除重复项。

 let numbers = [2, 2, 3, 3, 5, 6, 6]; const removeDups = array => { return array.reduce((acc, inc) => { if (!acc.find(i => i === inc)) { acc.push(inc); } return acc; }, []); } console.log(removeDups(numbers)); /// [2,3,5,6]

在我使用对象的用例中,上面的对象答案似乎对我不起作用。

我已将其修改如下:

var j = {};

this.forEach( function(v) {
   var typ = typeof v;
   var v = (typ === 'object') ? JSON.stringify(v) : v;

   j[v + '::' + typ] = v;
});

return Object.keys(j).map(function(v){
  if ( v.indexOf('::object') > -1 ) {
    return JSON.parse(j[v]);
  }

  return j[v];
});

这似乎现在可以正确地用于对象、数组、具有混合值的数组、布尔值等。

 var numbers = [1, 1, 2, 3, 4, 4]; function unique(dupArray) { return dupArray.reduce(function(previous, num) { if (previous.find(function(item) { return item == num; })) { return previous; } else { previous.push(num); return previous; } }, []) } var check = unique(numbers); console.log(check);

过滤掉未定义和空值,因为大多数时候您不需要它们。

const uniques = myArray.filter(e => e).filter((e, i, a) => a.indexOf(e) === i);

或者

const uniques = [...new Set(myArray.filter(e => e))];

有时我需要从一组对象中获取唯一的匹配项。 Lodash 似乎是一个很好的帮手,但我认为过滤数组不能证明向项目添加依赖项是合理的。

让我们假设两个对象的比较在比较一个属性时构成,例如一个 id。

const a = [{id: 3}, {id: 4}, {id: 3}, {id: 5}, {id: 5}, {id: 5}];

由于我们都喜欢单行片段,因此可以这样做:

a.reduce((acc, curr) => acc.find(e => e.id === curr.id) ? acc : [...acc, curr], [])

此解决方案应该非常快,并且在许多情况下都可以使用。

  1. 将索引数组项转换为对象键
  2. 使用 Object.keys 函数

    var indexArray = ["hi","welcome","welcome",1,-9]; var keyArray = {}; indexArray.forEach(function(item){ keyArray[item]=null; }); var uniqueArray = Object.keys(keyArray);

我有一个简单的例子,我们可以从数组中删除对象中具有重复 id 的对象,

  let data = new Array({id: 1},{id: 2},{id: 3},{id: 1},{id: 3});
  let unique = [];
  let tempArr = [];
  console.log('before', data);
  data.forEach((value, index) => {
    if (unique.indexOf(value.id) === -1) {
      unique.push(value.id);
    } else {
      tempArr.push(index);    
    }
  });
  tempArr.reverse();
  tempArr.forEach(ele => {
    data.splice(ele, 1);
  });
  console.log(data);

最简单的方法是将值转换为字符串以过滤嵌套对象值。

const uniq = (arg = []) => {
  const stringifyedArg = arg.map(value => JSON.stringify(value))
  return arg.filter((value, index, self) => {
    if (typeof value === 'object')
      return stringifyedArg.indexOf(JSON.stringify(value)) === index
    return self.indexOf(value) === index
  })
}

    console.log(uniq([21, 'twenty one', 21])) // [21, 'twenty one']
    console.log(uniq([{ a: 21 }, { a: 'twenty one' }, { a: 21 }])) // [{a: 21}, {a: 'twenty one'}]

就我而言,这是最简单的解决方案

 // A way to check if the arrays are equal const a = ['A', 'B', 'C'].sort().toString() const b = ['A', 'C', 'B'].sort().toString() console.log(a === b); // true // Test Case const data = [ { group: 'A', name: 'SD' }, { group: 'B', name: 'FI' }, { group: 'A', name: 'SD' }, { group: 'B', name: 'CO' } ]; // Return a new Array without dublocates function unique(data) { return data.reduce(function (accumulator, currentValue) { // Convert to string in order to check if they are the same value. const currentKeys = Object.keys(currentValue).sort().toString(); const currentValues = Object.values(currentValue).sort().toString(); let hasObject = false for (const obj of accumulator) { // Convert keys and values into strings so we can // see if they are equal with the currentValue const keys = Object.keys(obj).sort().toString(); const values = Object.values(obj).sort().toString(); // Check if keys and values are equal if (keys === currentKeys && values === currentValues) { hasObject = true } } // Push the object if it does not exist already. if (!hasObject) { accumulator.push(currentValue) } return accumulator }, []); } // Run Test Case console.log(unique(data)); // [ { group: 'A', name: 'SD' }, { group: 'B', name: 'FI' }, { group: 'B', name: 'CO' } ]

使用猫鼬,我有一组ObjectId可以使用。

我有一个要使用的对象 ID 的数组/列表,首先需要将其设置为字符串,然后在唯一集之后修改回对象 ID。

 var mongoose = require('mongoose') var ids = [ObjectId("1"), ObjectId("2"), ObjectId("3")] var toStringIds = ids.map(e => '' + e) let uniqueIds = [...new Set(toStringIds)] uniqueIds = uniqueIds.map(b => mongoose.Types.ObjectId(b)) console.log("uniqueIds :", uniqueIds)

一种可扩展、快速、高效且易于阅读的现代方法,使用iter-ops库:

import {pipe, distinct} from 'iter-ops';

const input = [1, 1, 2, 2, 2, 3]; // our data

const i = pipe(input, distinct()); // distinct iterable

console.log([...i]); //=> [1, 2, 3]

如果您的输入是一个对象数组,您只需为distinct运算符提供一个键选择器。

永远记住,内置方法很容易使用。 但请记住,它们具有复杂性。

基本逻辑是最好的。 没有隐藏的复杂性。

let list = [1, 1, 2, 100, 2] // your array
let check = {}
list = list.filter(item => {
    if(!check[item]) {
        check[item] = true
        return true;
    }
})

或者,如果您需要将来遍历检查的项目,请使用 let check = [](虽然会浪费内存)

ES2016 .includes() 一种方法简单答案:

var arr = [1,5,2,4,1,6]
function getOrigs(arr) {
  let unique = []
  arr && arr.forEach(number => {
    !unique.includes(number) && unique.push(number)
    if (number === arr[arr.length - 1]) {
      console.log('unique: ', unique)
    }
  })
}
getOrigs(arr)

改用这个:

  • 更高版本的 ES
  • 简单的问题不应该使用多种高级 JS 方法并且 push()、length() 和 forEach() 很常见
  • 使用闭包更易于阅读
  • 在内存、垃圾收集和性能方面似乎比其他更好
  • 更少的代码行:如果您根据行尾的位置分隔行,则只需要一行逻辑(因此您可以根据需要调用或重构这一行):
var arr = [1,5,2,4,1,6];
function getOrigs(arr) {let unique = []; 
  arr && arr.forEach(number => !unique.includes(number) && unique.push(number) && ((number === arr[arr.length - 1]) && console.log('unique: ', unique)))};
getOrigs(arr);

使用 ES6(单行)

原始值数组

let originalArr= ['a', 1, 'a', 2, '1'];

let uniqueArr = [...new Set(originalArr)];

对象数组

let uniqueObjArr = [...new Map(originalObjArr.map((item) => [item["propertyName"], item])).values()];

const ObjArray = [
    {
        name: "Eva Devore",
        character: "Evandra",
        episodes: 15,
    },
    {
        name: "Alessia Medina",
        character: "Nixie",
        episodes: 15,
    },
    {
        name: "Kendall Drury",
        character: "DM",
        episodes: 15,
    },
    {
        name: "Thomas Taufan",
        character: "Antrius",
        episodes: 14,
    },
    {
        name: "Alessia Medina",
        character: "Nixie",
        episodes: 15,
    },
];

let uniqueObjArray = [...new Map(ObjArray.map((item) => [item["id"], item])).values()];

尝试这样做:

 let d_array = [1, 2, 2, 3, 'a', 'b', 'b', 'c']; d_array = d_array.filter((x,i)=>d_array.indexOf(x)===i); console.log(d_array); // [1, 2, 3, "a", "b", "c"]

这遍历数组,检查数组中相同条目的第一个找到的结果是否是当前索引,如果是,则允许它在数组中。

我想从对象数组中删除重复项。 重复项具有相同的 ID。 这是我所做的。

// prev data
const prev = [
  {
    id: 1,
    name: "foo",
  },
  {
    id: 2,
    name: "baz",
  },
  {
    id: 1,
    name: "foo",
  },
];

// method:
// Step 1: put them in an object with the id as the key. Value of same id would get overriden.
// Step 2: get all the values.

const tempObj = {};
prev.forEach((n) => (tempObj[n.id] = n));
const next = Object.values(tempObj);

// result
[
  {
    id: 1,
    name: "foo",
  },
  {
    id: 2,
    name: "baz",
  }
];

另一个答案,只是因为我为我的特定用例写了一个。 无论如何,我碰巧对数组进行了排序,并且鉴于我正在排序,我可以使用它来进行重复数据删除。

请注意,我的排序处理我的特定数据类型,您可能需要不同的排序,具体取决于您拥有的元素类型。

var sortAndDedup = function(array) {
  array.sort(function(a,b){
    if(isNaN(a) && isNaN(b)) { return a > b ? 1 : (a < b ? -1 : 0); }
    if(isNaN(a)) { return 1; }
    if(isNaN(b)) { return -1; }
    return a-b;
  });

  var newArray = [];
  var len = array.length;
  for(var i=0; i<len; i++){
    if(i === 0 || array[i] != array[i-1]){
      newArray.push(array[i]);
    }
  }
};

此脚本修改数组,过滤掉重复值。 它适用于数字和字符串。

https://jsfiddle.net/qsdL6y5j/1/

    Array.prototype.getUnique = function () {
        var unique = this.filter(function (elem, pos) {
            return this.indexOf(elem) == pos;
        }.bind(this));
        this.length = 0;
        this.splice(0, 0, unique);
    }

    var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    duplicates.getUnique();
    alert(duplicates);

相反,此版本允许您返回一个具有唯一值的新数组,保留原始值(只需传递 true)。

https://jsfiddle.net/dj7qxyL7/

    Array.prototype.getUnique = function (createArray) {
        createArray = createArray === true ? true : false;
        var temp = JSON.stringify(this);
        temp = JSON.parse(temp);
        if (createArray) {
            var unique = temp.filter(function (elem, pos) {
                return temp.indexOf(elem) == pos;
            }.bind(this));
            return unique;
        }
        else {
            var unique = this.filter(function (elem, pos) {
                return this.indexOf(elem) == pos;
            }.bind(this));
            this.length = 0;
            this.splice(0, 0, unique);
        }
    }

    var duplicates = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    console.log('++++ ovveride')
    duplicates.getUnique();
    console.log(duplicates);
    console.log('++++ new array')
    var duplicates2 = [0, 0, 1, 1, 2, 3, 1, 1, 0, 4, 4];
    var unique = duplicates2.getUnique(true);
    console.log(unique);
    console.log('++++ original')
    console.log(duplicates2);

Browser support:

Feature Chrome  Firefox (Gecko)     Internet Explorer   Opera   Safari
Basic support   (Yes)   1.5 (1.8)   9                   (Yes)   (Yes)

你可以试试这个:

function removeDuplicates(arr){
  var temp = arr.sort();
  for(i = 0; i < temp.length; i++){
    if(temp[i] == temp[i + 1]){
      temp.splice(i,1);
      i--;
    }
  }
  return temp;
}

我会对数组进行排序,然后所有重复项都是邻居。 然后遍历数组并消除所有重复项。

function getUniques(array) {
  var l = array.length
  if(l > 1) {
    // get a cloned copy and sort it
    array = [...array].sort();
    var i = 1, j = 0;
    while(i < l) {
      if(array[i] != array[j]) {
        array[++j] = array[i];
      }
      i++;
    }
    array.length = j + 1;
  }
  return array;
}

这是使用比较器的另一种方法(我更关心干净的代码而不是性能):

const list = [
    {name: "Meier"},
    {name: "Hans"},
    {name: "Meier"},
]
const compare = (a, b) => a.name.localeCompare(b.name);
const uniqueNames = list.makeUnique(compare);
uniqueNames.pushIfAbsent({name: "Hans"}, compare);

原型声明:

declare global {
    interface Array<T>  {
        pushIfAbsent(item: T, compare:(a:T, b:T)=>number): number;
    }
    interface Array<T>  {
        makeUnique(compare:(a:T, b:T)=>number): Array<T>;
    }
}
Array.prototype.pushIfAbsent = function <T>(this:T[], item:T, compare:(a:T, b:T)=>number) {
    if (!this.find(existing => compare(existing, item)===0)) {
        return this.push(item)
    } else {
        return this.length;
    }
}
Array.prototype.makeUnique = function <T>(this:T[], compare:(a:T, b:T)=>number) {
    return this.filter((existing, index, self) => self.findIndex(item => compare(existing, item) == 0) == index);
}

如果您想就地更改它(而不是创建新数组),您可以:

var
  uniq = function uniq(array) {
    var
      len = array.length;

    while (len--) {
      if (array.indexOf(array[len]) !== len) {
        array.splice(len, 1);
      }
    }

    return array;
  },

  myArray = [1, 2, 2, 4, 2];

console.log(uniq(myArray));
// [1, 2, 4];

 (function() { "use strict"; Array.prototype.unique = function unique() { var self = this; return self.filter(function(a) { var that = this; // console.log(that); return !that[a] ? that[a] = true : false; }, {}); } var sampleArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; var distinctArray = sampleArray.unique(); console.log(distinctArray); })();
 Here is the simple way to solve this problem...

我使用 Array#reduce 作为创建 Array#unique 的方式

 Array.prototype.unique = function() { var object = this.reduce(function(h, v) { h[v] = true; return h; }, {}); return Object.keys(object); } console.log(["a", "b", "c", "b", "c", "a", "b"].unique()); // => ["a", "b", "c"]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM