ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一组数字,我需要确保它们是唯一的。我在互联网上找到了下面的代码片段,它工作得很好,直到数组中有一个零。我在 Stack Overflow 上发现 this other script 看起来几乎一模一样,但它并没有失败。

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

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

来自重复问题的更多答案:

从 JS 数组中删除重复值

类似的问题:

获取数组中的所有非唯一值(即:重复/多次出现)

@hippietrail 那个较老的问题是关于仅查找和返回重复项(我也很困惑!)。我的问题更多是关于为什么当数组中有零时这个函数会失败。
对于未来的读者,当您开始发现您必须始终通过算法修改数据结构的内容(对它们进行排序、删除重复元素等)或在每次迭代时搜索其中的元素时,可以安全地假设您'首先使用了错误的数据结构,然后开始使用更适合手头任务的数据结构(在这种情况下是哈希集而不是数组)。
我从其他地方复制了代码,很久以前......但它看起来很简单:o = objecta = arrayi = indexe =嗯,有些东西:P
只是想指出,很多人建议使用 JavaScript Set 作为解决方案,请谨慎使用,因为 Internet Explorer 不支持它。如果您必须支持 IE,请使用 polyfill。

E
Eric Bishard

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

function onlyUnique(value, index, self) { return self.indexOf(value) === index; } // 用法示例: var a = ['a', 1, 'a', 2, '1']; var unique = a.filter(onlyUnique);控制台.log(唯一); // ['a', 1, 2, '1']

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

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

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

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

对于不支持本机方法 filterindexOf 的旧浏览器 (filter 和 indexOf 的变通方法。

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

使用 ES6,这可以缩短为:

// 使用示例: var myArray = ['a', 1, 'a', 2, '1']; var unique = myArray.filter((v, i, a) => a.indexOf(v) === i);控制台.log(唯一); // 唯一的是 ['a', 1, 2, '1']

感谢 Camilo Martin 的评论提示。

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

var myArray = ['a', 1, 'a', 2, '1']; let unique = [...new Set(myArray)];控制台.log(唯一); // 唯一的是 ['a', 1, 2, '1']

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


不幸的是,此解决方案的运行速度会慢得多。您循环了两次,一次使用过滤器,一次使用索引
在现代 JS 中:.filter((v,i,a)=>a.indexOf(v)==i)(粗箭头符号)。
let unique_values = [...new Set(random_array)]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
为什么需要 [... ... ]new Set(myArray) 本身似乎具有相同的行为
以免任何新手被性能影响吓跑,考虑“慢得多”很可能是纳秒。如果您的数组相对较小(数百或更少),那么使用像这样简洁的一次性版本对于性能之外的原因(即可读性和可维护性)是好的。但是套装版本非常简洁明了。
m
mikemaccana

ES6/ES2015 的更新答案:使用 Setthe spread operator(感谢 le-m),单行解决方案是:

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

哪个返回

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

请注意,内部数组不起作用 Array.from(new Set([[1,2],[1,2],[1,2,3]]))
请注意,如果您使用 Set 并添加对象而不是原始值,它将包含对对象的唯一引用。因此,let s = new Set([{Foo:"Bar"}, {Foo:"Bar"}]); 中的集合 s 将返回:Set { { Foo: 'Bar' }, { Foo: 'Bar' } },它是一个具有对包含相同值的对象的唯一对象引用的 Set。如果您编写 let o = {Foo:"Bar"};,然后创建一个包含两个 references 的集合,如下所示:let s2 = new Set([o,o]);,那么 s2 将是 Set { { Foo: 'Bar' } }
如果有人想知道,这也适用于字符串,例如 [...new Set(["apple","apple","orange"])] 结果为 ['apple', 'orange'] 。伟大的!
在 Typescript 中,使用 Array.from( new Set( items ) )
M
Max Makhrov

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

使用 object { } 防止重复 使用辅助数组 [ ] 使用 filter + indexOf 奖励! ES6 设置方法。

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

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

使用过滤器 + 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)];
}

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

https://i.stack.imgur.com/EqG6p.png

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

2020 年更新

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


Makrov,所以 uniqueItems = [...new Set(items)] 似乎是所有方法中最快和最简洁的?
您的解决方案仅处理原语,它不适用于对象,您需要 JSON.stringify 哈希中的 v
R
Ruslan López

您也可以使用 underscore.js

console.log(_.uniq([1, 2, 1, 3, 1, 4]));

这将返回:

[1, 2, 3, 4]

请大家这样做。不要把东西插到 Array 原型上。请。
@JacobDalton 请不要这样做。无需为可以使用 array = [...new Set(array)] 完成的小工作添加额外的库
@JacobDalton 为什么不呢?将某些东西“顶起”到阵列上是否有不利之处?
C
Community

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

https://i.stack.imgur.com/TfGaP.png

使用 ES5 语法

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

浏览器兼容性:IE9+


O
OXiGEN

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

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

const cars = ['沃尔沃', '吉普车', '沃尔沃', '林肯', '林肯', '福特']; const uniqueCars = Array.from(new Set(cars)); console.log(uniqueCars);

Array.from 对于将 Set 转换回数组很有用,这样您就可以轻松访问数组拥有的所有很棒的方法(功能)。也有other ways做同样的事情。但是您可能根本不需要 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) 部分变成我们命名为 result 的东西。

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


如果我希望新数组不是唯一的,而是一个重复的值数组,这将如何工作?所以使用上面的例子,我正在寻找的数组是 ["volvo","lincoln"]
@Jason 我可能会创建一个 Map 来存储以前看到的项目和一个数组来存储重复的项目。然后遍历 cars 数组并检查 Map 是否有当前项,如果有则将其推送到重复数组,如果没有则将其添加到 Map。如果您创建一个新问题,我很乐意为您创建一个代码示例,我们可以在那里继续讨论。
J
Jerome

使用 ES6 新设置

var 数组 = [3,7,5,3,2,5,2,7]; var unique_array = [...new Set(array)]; console.log(unique_array); // 输出 = [3,7,5,2]

使用 For 循环

var 数组 = [3,7,5,3,2,5,2,7]; for(var i=0;i


M
Mottie

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

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

注意:此代码是从 Paul Irish's duck punching post 中提取的 - 我忘了注明:P


一个简洁的解决方案,但调用 inArray 的效率低于调用 hasOwnProperty。
这也是 O(N^2),对吧?而字典或 hasOwnProperty 方法可能是 O(N*logN)。
m
mdmundo

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

在此之前几年给出的其他答案完全重复。
t
tagurit

最简单的 fastest(在 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,这个函数是 the fastest of the ones I could find anywhere - 随意添加你自己的。

非原型版本:

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 浏览器中的 faster than the above method


在 Linux 上,Chrome 55.0.2883 更喜欢您的 arr.unique() 而 swilliams 的 arrclone2.sortFilter() 最慢(慢 78%)。然而,Firefox 51.0.0(有很多插件)的 swilliams 最快(但仍然比任何其他 Chrome 结果慢),而 mottie 的 jQuery $.grep(arr, jqFilter) 最慢(慢 46%)。你的 arr.uniq() 慢了 30%。我将每个测试运行了两次并得到了一致的结果。 Rafael 的arr.getUnique() 在两个浏览器中均获得第二名。
jsPerf 目前是 buggy,所以我对这个测试的编辑并没有提交所有内容,但它确实导致添加了两个测试:Cocco 的 toUnique() 在两个浏览器上都击败了 Vamsi 的 ES6 list.filter(),击败了 swilliams 的 sortFilter()在 FF 上排名第一(sortFilter 慢了 16%)并在 Chrome 上击败了你的排序测试(慢了 2%)。
啊,我没有发现那些测试很小而且并不重要。对已接受答案 describes that problem 的注释并在 revision 中对测试进行更正,其中 Rafael 的代码很容易最快,而 Joetje50 的 arr.unique 代码慢 98%。如 this comment 中所述,我还进行了另一次修订。
好吧,实际上您在 unique 函数中实现的算法具有 O(n^2) 复杂度,而 getUnique 中的算法是 O(n)。第一个在小型数据集上可能更快,但你怎么能与数学争论:) 如果你在一组 1e5 个独特项目上运行它,你可以确保后者更快
也由 lodash.uniq 用于 input_array.length < 200,否则使用 [...new Set(input_array)] 方法。表示为减速器:input_array.reduce((c, v) => {if (!c.includes(v)) c.push(v); return c;}, [])
v
vsync

我们可以使用 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]


K
Kamil Kiełczewski

魔法

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

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

让 t, unique= a=> ( t={}, a.filter(e=>!(t[e]=e in t)) ); // 使用全局 t 的“独立”版本: // a1.filter((t={},e=>!(t[e]=e in t))); // 测试数据 let a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];令 a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12 ]];让a3 = ['迈克','亚当','马特','南希','亚当','珍妮','南希','卡尔']; // 结果 console.log(JSON.stringify( unique(a1) )) console.log(JSON.stringify( unique(a2) )) console.log(JSON.stringify( unique(a3) ))


这看起来太酷了,如果没有可靠的解释,我觉得当我运行它时你会挖比特币
我的意思是你应该用一些解释来扩展你的答案并评论它的解构。不要指望人们会找到这样有用的答案。 (虽然它看起来真的很酷,但可能有效)
不是魔术,而是很像“Set”答案,在字典中使用 O(1) 键查找。你需要增加计数器吗? “e=>!(t[e]=e in t)”怎么样。不错的答案。
@Jeppe 当我运行您的改进时,我体验了 aha effect (在我不知道我可以在 for 循环之外的其他构造之外使用 in 运算符之前) - 谢谢 - 我很感激,并将给予+2 你的其他好答案。
s
sergeyz
["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;
 }, []);

G
Gajus

这个原型 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"]


请注意,$foo = 'bar' 是声明变量的 PHP 方式。它可以在 javascript 中工作,但会创建一个隐式全局,通常不应该这样做。
@CamiloMartin 抱歉,但您错了, $foo 是全局的,因为该示例不在闭包中,并且他缺少 var 关键字。与美元无关jsfiddle.net/robaldred/L2MRb
@Rob 这正是我要说的,PHP 人会认为 $foo 是在 javascript 中声明变量的方式,而实际上 var foo 是。
G
Giacomo Casadei

您可以简单地使用内置函数 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);控制台.log(newarr);


v
vsync

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

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

注意 - 此解决方案不保留顺序,因为它从左到右删除了重复的项目,但如果 Array 是对象的集合,它会赢得 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( // 用空数组初始化并填充非重复 list.reduce((acc, v) => (!acc.includes(v) && acc.push(v), acc), []) ) // [0,1,2,3,"a ","b",4,5]


不幸的是,这会保留每个值的最后一个实例,而不是第一个。 (这可能没问题,但我认为保留第一个通常是预期的)
虽然这是一个很好的优化想法,但我认为人们不会想要使用它,因为这会保留最后一项,这基本上会弄乱数组顺序。
i
ifelse.codes
[...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]

虽然此代码可能会解决问题,但包括 explanation 说明如何以及为何解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请编辑您的答案以添加解释,并说明适用的限制和假设。
与此日期前一年的 previous answer 相同
D
Dave

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

很多答案是这样的:

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

很好的解决方案,请注意新数组将从函数返回。 (它不会自行修改)
作品将处理复杂的对象数组
@EdgarQuintero 仅当元素实际上是完全相同的对象时,如果您使用 indexOf 解决方案,数组 [ { a: 2 }, { a: 2 } ] 不会像许多人期望的那样工作,但是 { 2} 解决方案可能有用
e
ephemient
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
}

我认为如果数组包含对象/数组,这将不起作用,而且我不确定它是否会保留标量的类型。
是的,一切都被字符串化了。这可以通过将原始值存储在 o 而不是仅 1 中来解决,尽管相等比较仍然是按字符串进行的(尽管在所有可能的 Javascript 相等中,它似乎并不太不合理)。
Array.prototype 只能使用不可枚举的方法进行扩展 .... Object.defineProperty(Array.prototype,"getUnique",{}) ... 但是使用辅助对象的想法非常好
C
Cœur

在不扩展 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 等)的开发。


它是 js 1.6 的事实并不意味着您不能使用 filter。在 MDN page 他们有一个 Internet Explorer 的实现,我的意思是,旧浏览器。另外:JS 1.6 仅指 Firefox 的 js 引擎,但正确的说法是它是 ECMAScript 5。
L
Luca Matteis

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

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


啊,好吧,我现在明白了……但是有一个简单的修复方法可以让它工作吗?
t
tagurit

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

var a = Array.uniq();  

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

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

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

因为我找到了更好的答案,所以我认为主题是针对所有人的,而不仅仅是针对提出问题的人
感谢时间机器,但 iirc 大约 15 年前 JS 社区进行了辩论,结果是 - 不要扩展原型的副作用,并导致你以这种方式污染所有 JS 数组。
K
Krishnadas PC

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

var 名称 = ["迈克","马特","南希","马特","亚当","珍妮","南希","卡尔"]; console.log([...new Set(names)])

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

var 名称 = ["迈克","马特","南希","马特","亚当","珍妮","南希","卡尔"]; var namesSorted = names.sort();常量结果 = namesSorted.filter((e, i) => namesSorted[i] != namesSorted[i+1]);控制台.log(结果);


d
demo

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

让 objArr = [{ id: '123' }, { id: '123' }, { id: '456' }]; objArr = objArr.reduce((acc, cur) => [ ...acc.filter((obj) => obj.id !== cur.id), cur ], []);控制台.log(objArr);


C
Constant Meiring

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

用法

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

npm install lodash

然后按如下方式使用它:

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

出去:

[ 1, 2, 3 ]

您还可以使用 lodash 从数组中删除具有重复属性的对象:_.uniqWith(objectArray, _.isEqual)
D
Dan Fox

我不确定为什么 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
  )

S
Saravanan Rajaraman

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

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]

这个答案怎么可能是正确的?根据给定 [1,4,2,7,1,5,9,2,4,7,2] 的输入,唯一数组的预期结果是 [5,9]
A
Adam Katz

看来我们已经失去了 Rafael's answer,这是几年来公认的答案。这是(至少在 2017 年)表现最好的解决方案 if you don't have a mixed-type array

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

d
daviestar

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

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

filter()findIndex() 不是都必须遍历数组吗?这将使这成为一个双循环,因此运行成本是此处任何其他答案的两倍。
@AdamKatz 是的,它会遍历数组 n+1 次。请注意,此处使用 map、filter、indexOf、reduce 等组合的其他答案也必须这样做,这是问题固有的。为避免,您可以使用 new Set() 或类似于 Grozz 答案的查找对象。
S
Shreyansh Sharma

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

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