从JS数组中删除重复值

时间:2012-02-10 14:53:23

标签: javascript arrays duplicates unique

我有一个非常简单的JavaScript数组,可能包含也可能不包含重复项。

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

我需要删除重复项并将唯一值放在新数组中。

我可以指出我尝试过的所有代码,但我认为它没用,因为它们不起作用。我也接受jQuery解决方案。

类似的问题:

53 个答案:

答案 0 :(得分:2845)

TL; DR

使用Set构造函数和spread syntax

uniq = [...new Set(array)];

“聪明”但天真的方式

uniqueArray = a.filter(function(item, pos) {
    return a.indexOf(item) == pos;
})

基本上,我们迭代数组,并为每个元素检查数组中此元素的第一个位置是否等于当前位置。显然,这两个位置对于重复元素是不同的。

使用过滤器回调的第3个(“this array”)参数,我们可以避免关闭数组变量:

uniqueArray = a.filter(function(item, pos, self) {
    return self.indexOf(item) == pos;
})

虽然简洁,但这种算法对于大型数组(二次时间)并不是特别有效。

拯救哈希表

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

通常这样做。我们的想法是将每个元素放在一个哈希表中,然后立即检查它的存在。这给了我们线性时间,但至少有两个缺点:

  • 由于散列键只能是JavaScript中的字符串,因此该代码不区分数字和“数字字符串”。也就是说,uniq([1,"1"])将只返回[1]
  • 出于同样的原因,所有对象都被认为是平等的:uniq([{foo:1},{foo:2}])将只返回[{foo:1}]

也就是说,如果你的数组只包含基元并且你不关心类型(例如它总是数字),那么这个解决方案是最优的。

两个世界中最好的

通用解决方案结合了两种方法:它使用基元的哈希查找和对象的线性搜索。

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

    return a.filter(function(item) {
        var type = typeof item;
        if(type in prims)
            return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
        else
            return objs.indexOf(item) >= 0 ? false : objs.push(item);
    });
}

排序| uniq的

另一种选择是先对数组进行排序,然后删除与前一个元素相等的每个元素:

function uniq(a) {
    return a.sort().filter(function(item, pos, ary) {
        return !pos || item != ary[pos - 1];
    })
}

同样,这不适用于对象(因为sort的所有对象都相同)。另外,我们默默地改变原始阵列作为副作用 - 不好!但是,如果您的输入已经排序,则可以采用此方式(只需从上面删除sort)。

独特的......

有时需要根据除了相等之外的某些标准来统一列表,例如,过滤掉不同的对象,但共享一些属性。这可以通过传递回调来优雅地完成。此“键”回调应用于每个元素,并删除具有相同“键”的元素。由于key预计会返回一个原语,因此哈希表在这里可以正常工作:

function uniqBy(a, key) {
    var seen = {};
    return a.filter(function(item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    })
}

一个特别有用的key()JSON.stringify,它会删除物理上不同但“看起来”相同的对象:

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
console.log(b) // [[1,2,3], [4,5,6]]

如果key不是原始的,则必须求助于线性搜索:

function uniqBy(a, key) {
    var index = [];
    return a.filter(function (item) {
        var k = key(item);
        return index.indexOf(k) >= 0 ? false : index.push(k);
    });
}

在ES6中,您可以使用Set

function uniqBy(a, key) {
    let seen = new Set();
    return a.filter(item => {
        let k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}

Map

function uniqBy(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

,它们也适用于非原始键。

第一个还是最后一个?

通过键删除对象时,您可能希望保留第一个“相等”对象或最后一个对象。

使用上面的Set变体保留第一个,Map保留最后一个:

function uniqByKeepFirst(a, key) {
    let seen = new Set();
    return a.filter(item => {
        let k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}


function uniqByKeepLast(a, key) {
    return [
        ...new Map(
            a.map(x => [key(x), x])
        ).values()
    ]
}

//

data = [
    {a:1, u:1},
    {a:2, u:2},
    {a:3, u:3},
    {a:4, u:1},
    {a:5, u:2},
    {a:6, u:3},
];

console.log(uniqByKeepFirst(data, it => it.u))
console.log(uniqByKeepLast(data, it => it.u))

underscoreLo-Dash都提供uniq方法。他们的算法基本上类似于上面的第一个片段,归结为:

var result = [];
a.forEach(function(item) {
     if(result.indexOf(item) < 0) {
         result.push(item);
     }
});

这是二次方的,但是还有很多额外的好东西,比如包装原生indexOf,通过键(iteratee的说法)进行统一的能力,以及对已排序数组的优化。

如果您正在使用jQuery,并且在没有任何一美元之前无法忍受任何事情,那就是这样:

  $.uniqArray = function(a) {
        return $.grep(a, function(item, pos) {
            return $.inArray(item, a) === pos;
        });
  }

这又是第一个片段的变体。

效果

JavaScript中的函数调用很昂贵,因此上述解决方案虽然简洁,但效率不高。为获得最佳性能,请用循环替换filter并删除其他函数调用:

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

这段丑陋的代码与上面的代码段#3相同,但速度提高了一个数量级(截至2017年,它只有两倍的速度 - JS核心人员做得很好! )

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

/////

var r = [0,1,2,3,4,5,6,7,8,9],
    a = [],
    LEN = 1000,
    LOOPS = 1000;

while(LEN--)
    a = a.concat(r);

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq(a);
document.write('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6提供Set对象,这使事情变得更加容易:

function uniq(a) {
   return Array.from(new Set(a));
}

let uniq = a => [...new Set(a)];

请注意,与python不同,ES6集按插入顺序迭代,因此此代码保留原始数组的顺序。

但是,如果您需要一个包含唯一元素的数组,为什么不从一开始就使用集合?

发电机

“懒惰”,基于生成器的uniq版本可以在相同的基础上构建:

  • 从参数
  • 获取下一个值
  • 如果已经看过,请跳过它
  • 否则,产生它并将其添加到已经看到的值集合

function* uniqIter(a) {
    let seen = new Set();

    for (let x of a) {
        if (!seen.has(x)) {
            seen.add(x);
            yield x;
        }
    }
}

// example:

function* randomsBelow(limit) {
    while (1)
        yield Math.floor(Math.random() * limit);
}

// note that randomsBelow is endless

count = 20;
limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {
    console.log(r);
    if (--count === 0)
        break
}

// exercise for the reader: what happens if we set `limit` less than `count` and why

答案 1 :(得分:407)

使用jQuery快速而肮脏:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
    if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});

答案 2 :(得分:299)

厌倦了使用for循环或jQuery看到所有不好的例子。 Javascript现在拥有完美的工具:排序,映射和缩小。

Uniq在保持现有订单的同时减少

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

var uniq = names.reduce(function(a,b){
    if (a.indexOf(b) < 0 ) a.push(b);
    return a;
  },[]);

console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

// one liner
return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);

更快的uniq与排序

可能有更快的方法,但这个方法相当不错。

var uniq = names.slice() // slice makes copy of array before sorting it
  .sort(function(a,b){
    return a > b;
  })
  .reduce(function(a,b){
    if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop())
    return a;
  },[]); // this empty array becomes the starting value for a

// one liner
return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]);

2015年更新:ES6版本:

在ES6中,您拥有集合和传播,这使得删除所有重复项非常容易和高效:

var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

根据事件排序:

有人询问是否根据有多少个唯一名称对结果进行排序:

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

var uniq = names
  .map((name) => {
    return {count: 1, name: name}
  })
  .reduce((a, b) => {
    a[b.name] = (a[b.name] || 0) + b.count
    return a
  }, {})

var sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b])

console.log(sorted)

答案 3 :(得分:91)

Vanilla JS:使用类似Set的对象

删除重复项

您可以随时尝试将其放入对象中,然后迭代其键:

function remove_duplicates(arr) {
    var obj = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        obj[arr[i]] = true;
    }
    for (var key in obj) {
        ret_arr.push(key);
    }
    return ret_arr;
}

Vanilla JS:通过跟踪已经看到的值来删除重复项(订单安全)

或者,对于订单安全版本,使用对象存储以前看到的所有值,并在添加到数组之前检查它的值。

function remove_duplicates_safe(arr) {
    var seen = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        if (!(arr[i] in seen)) {
            ret_arr.push(arr[i]);
            seen[arr[i]] = true;
        }
    }
    return ret_arr;

}

ECMAScript 6:使用新的设置数据结构(订单安全)

ECMAScript 6添加了新的Set数据结构,可以存储任何类型的值。 Set.values以插入顺序返回元素。

function remove_duplicates_es6(arr) {
    let s = new Set(arr);
    let it = s.values();
    return Array.from(it);
}

使用示例:

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

b = remove_duplicates(a);
// b:
// ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

c = remove_duplicates_safe(a);
// c:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

d = remove_duplicates_es6(a);
// d:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

答案 4 :(得分:69)

使用Underscore.js

它是一个包含许多用于操作数组的函数的库。

  

这与jQuery的tux以及Backbone.js相关   背带。

<强> _.uniq

  

_.uniq(array, [isSorted], [iterator]) 别名: 唯一
  使用===来测试对象,生成数组的无副本版本   平等。如果您事先知道数组已排序,则传递    isSorted true 将运行更快的算法。如果你想   根据转换计算唯一项,传递迭代器   功能

<强> Example

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

alert(_.uniq(names, false));

注意:Lo-Dashunderscore竞争对手)也提供了可比较的.uniq实施。

答案 5 :(得分:67)

使用数组过滤器和indexOf函数的单行版本:

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

答案 6 :(得分:52)

您可以使用filter方法的第二个索引参数在JavaScript中执行此操作:

var a = [2,3,4,5,5,4];
a.filter(function(value, index){ return a.indexOf(value) == index });

或简称

a.filter((v,i) => a.indexOf(v) == i)

答案 7 :(得分:45)

一行:

let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);

答案 8 :(得分:32)

使用本机javascript函数从数组中删除重复项的最简洁方法是使用如下序列:

vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])

在reduce函数中不需要sliceindexOf,就像我在其他示例中看到的那样!然而,将它与过滤器功能一起使用是有意义的:

vals.filter(function(v, i, a){ return i == a.indexOf(v) })

另一种已经在少数浏览器上运行的ES6(2015)方法是:

Array.from(new Set(vals))

甚至使用spread operator

[...new Set(vals)]

喝彩!

答案 9 :(得分:28)

  

像这样使用Array.filter()

&#13;
&#13;
var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana'];

console.log('Actual Array: ' + actualArr);

var filteredArr = actualArr.filter(function(item, index) {
  if (actualArr.indexOf(item) == index)
    return item;
});

console.log('Filtered Array: ' + filteredArr);
&#13;
&#13;
&#13;

这可以在ES6中缩短为

actualArr.filter((item,index,self) => self.indexOf(item)==index);

Here很好地解释了Array.filter()

答案 10 :(得分:19)

去找这个:

var uniqueArray = duplicateArray.filter(function(elem, pos) {
    return duplicateArray.indexOf(elem) == pos;
}); 

现在uniqueArray不包含重复项。

答案 11 :(得分:18)

最简单的一个我到目前为止已经遇到过。在es6。

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

 var noDupe = Array.from(new Set(names))

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

答案 12 :(得分:16)

我已经在其他一些问题上对dupes删除进行了详细的比较,但是我注意到这是我想在这里分享它的真实地方。

我相信这是最好的方法

&#13;
&#13;
var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{}));
console.log(reduced);
&#13;
&#13;
&#13;

好吧..即使这个是O(n)而其他人都是O(n ^ 2)我很想看到这个缩小/查找表和filter / indexOf组合之间的基准比较(我选择Jeetendras非常好实施https://stackoverflow.com/a/37441144/4543207)。我准备一个100K项目数组,填充0-9999范围内的随机正整数,并删除重复项。我重复测试了10次,结果的平均值表明它们的性能不匹配。

  • 在firefox v47中减少&amp; lut:14.85ms vs filter&amp; indexOf:2836ms
  • 在chrome v51中减少&amp; lut:23.90ms vs filter&amp; indexOf:1066ms

好到目前为止一切都那么好。但是这次以ES6风格正确地做到了。它看起来很酷..!但截至目前,它对抗强大的解决方案将如何表现对我来说是一个谜。让我们先看看代码然后对它进行基准测试。

&#13;
&#13;
var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];
console.log(reduced);
&#13;
&#13;
&#13;

哇,这很短......!但是性能怎么样?它非常漂亮......由于过滤器/ indexOf的重量超过了我们的肩膀,我现在可以在0..99999范围内测试一组1M的正整数随机项,以获得10次连续测试的平均值。我可以说这一次它是一场真正的比赛。自己看结果:)

&#13;
&#13;
var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 10;
for (var i = 0; i<count; i++){
  ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");
&#13;
&#13;
&#13;

你会使用哪一个..?好吧不是那么快......!不要被欺骗。地图处于位移状态。现在看......在上述所有情况下,我们填充一个大小为n的数组,其数量为&lt; ñ。我的意思是我们有一个100的数组,我们用随机数0..9填充所以有明确的重复和&#34;几乎&#34;绝对每个数字都有重复。如果我们用随机数0..9999填充大小为100的数组怎么样。现在让我们看看地图在家玩。这次是100K项目的数组,但是随机数范围是0..100M。我们将进行100次连续测试以平均结果。好的,让我们看看赌注..! &lt; - 没有拼写错误

&#13;
&#13;
var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");
&#13;
&#13;
&#13;

现在这是Map()的壮观复出..!可能现在你可以在想要删除欺骗时做出更好的决定。

好吧,我们现在都很高兴。但是主角一直伴随着掌声。我相信你们有些人想知道Set对象会做什么。既然我们对ES6持开放态度并且我们知道Map是之前游戏的赢家,那么让我们将Map与Set进行比较。这次典型的皇马对阵巴塞罗那比赛......或者是这样?让我们看看谁将赢得el classico:)

&#13;
&#13;
var ranar = [],
     red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     red2 = a => Array.from(new Set(a)),
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("map & spread took: " + avg1 + "msec");
console.log("set & A.from took: " + avg2 + "msec");
&#13;
&#13;
&#13;

哇..男人..!出乎意料的是,它根本没有成为一个经典之作。更像是巴塞罗那足球俱乐部对阵CA Osasuna:))

答案 13 :(得分:15)

以下内容比列出的jQuery方法快80%以上(参见下面的测试)。 这是几年前类似问题的答案。如果我遇到最初提出它的人,我会发布信用证。 纯JS。

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

我的测试用例比较: http://jsperf.com/remove-duplicate-array-tests

答案 14 :(得分:14)

以下是对该问题的简单回答。

var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"];
var uniqueNames = [];

    for(var i in names){
        if(uniqueNames.indexOf(names[i]) === -1){
            uniqueNames.push(names[i]);
        }
    }

答案 15 :(得分:14)

在ECMAScript 6(又名ECMAScript 2015)中,Set可用于过滤掉重复项。然后可以使用spread operator将其转换回数组。

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

答案 16 :(得分:14)

解决方案1 ​​

Array.prototype.unique = function() {
    var a = [];
    for (i = 0; i < this.length; i++) {
        var current = this[i];
        if (a.indexOf(current) < 0) a.push(current);
    }
    return a;
}

解决方案2(使用Set)

Array.prototype.unique = function() {
    return Array.from(new Set(this));
}

<强>测试

var x=[1,2,3,3,2,1];
x.unique() //[1,2,3]

<强>性能

当我测试chrome的性能(使用和不使用Set)时,我发现使用Set的实现要快得多!

Array.prototype.unique1 = function() {
    var a = [];
    for (i = 0; i < this.length; i++) {
        var current = this[i];
        if (a.indexOf(current) < 0) a.push(current);
    }
    return a;
}


Array.prototype.unique2 = function() {
    return Array.from(new Set(this));
}

var x=[];
for(var i=0;i<10000;i++){
	x.push("x"+i);x.push("x"+(i+1));
}

console.time("unique1");
console.log(x.unique1());
console.timeEnd("unique1");



console.time("unique2");
console.log(x.unique2());
console.timeEnd("unique2");

答案 17 :(得分:10)

一种简单但有效的技巧,是将filter方法与过滤器function(value, index){ return this.indexOf(value) == index }结合使用。

代码示例:

var data = [2,3,4,5,5,4];
var filter = function(value, index){ return this.indexOf(value) == index };
var filteredData = data.filter(filter, data );

document.body.innerHTML = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

另见this Fiddle

答案 18 :(得分:9)

这里是没有任何特殊库的简单方法是特殊功能,

&#13;
&#13;
name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; })

console.log("Original name list:"+name_list.length, name_list)
console.log("\n Unique name list:"+get_uniq.length, get_uniq)
&#13;
&#13;
&#13;

enter image description here

答案 19 :(得分:8)

除了比当前答案更简单,更简洁的解决方案(减去未来的ES6解决方案)之外,我还对此进行了测试,并且速度也快得多:

var uniqueArray = dupeArray.filter(function(item, i, self){
  return self.lastIndexOf(item) == i;
});

有一点需要注意:在IE9中添加了Array.lastIndexOf(),所以如果你需要低于此值,你需要寻找其他地方。

答案 20 :(得分:8)

所以选项是:

let a = [11,22,11,22];
let b = []


b = [ ...new Set(a) ];     
// b = [11, 22]

b = Array.from( new Set(a))   
// b = [11, 22]

b = a.filter((val,i)=>{
  return a.indexOf(val)==i
})                        
// b = [11, 22]

答案 21 :(得分:7)

通用功能方法

这是ES2015的一种通用且严格功能的方法:

&#13;
&#13;
// small, reusable auxiliary functions

const apply = f => a => f(a);

const flip = f => b => a => f(a) (b);

const uncurry = f => (a, b) => f(a) (b);

const push = x => xs => (xs.push(x), xs);

const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const some = f => xs => xs.some(apply(f));


// the actual de-duplicate function

const uniqueBy = f => foldl(
   acc => x => some(f(x)) (acc)
    ? acc
    : push(x) (acc)
 ) ([]);


// comparators

const eq = y => x => x === y;

// string equality case insensitive :D
const seqCI = y => x => x.toLowerCase() === y.toLowerCase();


// mock data

const xs = [1,2,3,1,2,3,4];

const ys = ["a", "b", "c", "A", "B", "C", "D"];


console.log( uniqueBy(eq) (xs) );

console.log( uniqueBy(seqCI) (ys) );
&#13;
&#13;
&#13;

我们可以轻松地从unique派生unqiueBy或使用Set s更快的实施:

const unqiue = uniqueBy(eq);

// const unique = xs => Array.from(new Set(xs));

这种方法的好处:

  • 使用单独的比较器功能的通用解决方案
  • 陈述性和简洁的实施
  • 重用其他小型通用函数

性能注意事项

uniqueBy与使用循环的命令式实现一样快,但由于其通用性,它更具表现力。

如果您在应用中将uniqueBy标识为具体性能损失的原因,请将其替换为优化代码。也就是说,首先以功能性的声明方式编写代码。之后,如果遇到性能问题,请尝试优化位置的代码,这是导致问题的原因。

内存消耗和垃圾收集

uniqueBy利用隐藏在其体内的突变(push(x) (acc))。它重用累加器而不是在每次迭代后丢弃它。这减少了内存消耗和GC压力。由于这个副作用被包裹在函数内部,所以外面的一切都是纯粹的。

答案 22 :(得分:5)

在任何地方(甚至在PhotoshopScript中)代码中理解和工作都非常简单。检查一下!

var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");

peoplenames = unique(peoplenames);
alert(peoplenames);

function unique(array){
    var len = array.length;
    for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) 
        if(array[j] == array[i]){
            array.splice(j,1);
            j--;
            len--;
        }
    return array;
}

//*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"]

答案 23 :(得分:5)

for (i=0; i<originalArray.length; i++) {  
    if (!newArray.includes(originalArray[i])) {
        newArray.push(originalArray[i]); 
    }
}

答案 24 :(得分:4)

如果您有任何机会使用

  

D3.js

你可以做到

d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]

https://github.com/mbostock/d3/wiki/Arrays#set_values

答案 25 :(得分:4)

$(document).ready(function() {

    var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"]

    var arr2=["cat","fish","mango","apple"]

    var uniquevalue=[];
    var seconduniquevalue=[];
    var finalarray=[];

    $.each(arr1,function(key,value){

       if($.inArray (value,uniquevalue) === -1)
       {
           uniquevalue.push(value)

       }

    });

     $.each(arr2,function(key,value){

       if($.inArray (value,seconduniquevalue) === -1)
       {
           seconduniquevalue.push(value)

       }

    });

    $.each(uniquevalue,function(ikey,ivalue){

        $.each(seconduniquevalue,function(ukey,uvalue){

            if( ivalue == uvalue)

            {
                finalarray.push(ivalue);
            }   

        });

    });
    alert(finalarray);
});

答案 26 :(得分:3)

尽管ES6解决方案是最好的,但我对于没有人展示以下解决方案感到困惑:

function removeDuplicates(arr){
    o={}
    arr.forEach(function(e){
        o[e]=true
    })
    return Object.keys(o)
}

这里要记住的是对象必须有唯一的键。我们正在利用它来删除所有重复项。我原以为这将是最快的解决方案(在ES6之前)。

请记住,这也会对数组进行排序。

答案 27 :(得分:3)

这只是另一种解决方案,但与其他解决方案不同。

function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  newArr.sort();
  var finalArr = [];
  for(var i = 0;i<newArr.length;i++) {
   if(!(newArr[i] === newArr[i+1] || newArr[i] === newArr[i-1])) {
     finalArr.push(newArr[i]);
   } 
  }
  return finalArr;
}

答案 28 :(得分:3)

略微修改thg435使用自定义比较器的优秀答案:

function contains(array, obj) {
    for (var i = 0; i < array.length; i++) {
        if (isEqual(array[i], obj)) return true;
    }
    return false;
}
//comparator
function isEqual(obj1, obj2) {
    if (obj1.name == obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr, x) && arr.push(x);
    });
}

答案 29 :(得分:3)

https://jsfiddle.net/2w0k5tz8/

function remove_duplicates(array_){
    var ret_array = new Array();
    for (var a = array_.length - 1; a >= 0; a--) {
        for (var b = array_.length - 1; b >= 0; b--) {
            if(array_[a] == array_[b] && a != b){
                delete array_[b];
            }
        };
        if(array_[a] != undefined)
            ret_array.push(array_[a]);
    };
    return ret_array;
}

console.log(remove_duplicates(Array(1,1,1,2,2,2,3,3,3)));

循环,删除重复项,并创建克隆数组占位符,因为数组索引不会更新。

向后循环以获得更好的性能(您的循环不需要继续检查数组的长度)

答案 30 :(得分:3)

这可能是永久删除数组中重复项的最快方法之一 比这里的大多数功能快10倍。&amp;野生动物园快78倍

function toUnique(a,b,c){               //array,placeholder,placeholder
 b=a.length;while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1)
}
  1. 测试:http://jsperf.com/wgu
  2. 演示:http://jsfiddle.net/46S7g/
  3. 更多:https://stackoverflow.com/a/25082874/2450730
  4. 如果你不能阅读上面的代码,请阅读javascript书或这里有一些关于更短代码的解释。 https://stackoverflow.com/a/21353032/2450730

答案 31 :(得分:2)

对于任何希望将具有重复元素的数组展平为一个唯一数组的人:

function flattenUniq(arrays) {
  var args = Array.prototype.slice.call(arguments);

  var array = [].concat.apply([], args)

  var result = array.reduce(function(prev, curr){
    if (prev.indexOf(curr) < 0) prev.push(curr);
    return prev;
  },[]);

  return result;
}

答案 32 :(得分:1)

在不编写大量代码的情况下执行此操作的另一种方法是使用ES5 Object.keys - 方法:

var arrayWithDuplicates = ['a','b','c','d','a','c'],
    deduper = {};
arrayWithDuplicates.forEach(function (item) {
    deduper[item] = null;
});
var dedupedArray = Object.keys(deduper); // ["a", "b", "c", "d"]

在函数中提取

function removeDuplicates (arr) {
    var deduper = {}
    arr.forEach(function (item) {
        deduper[item] = null;
    });
    return Object.keys(deduper);
}

答案 33 :(得分:1)

嵌套循环方法,用于删除数组中的重复项并保留元素的原始顺序。

var array = [1, 3, 2, 1, [5], 2, [4]]; // INPUT

var element = 0;
var decrement = array.length - 1;
while(element < array.length) {
  while(element < decrement) {
    if (array[element] === array[decrement]) {
      array.splice(decrement, 1);
      decrement--;
    } else {
      decrement--;
    }
  }
  decrement = array.length - 1;
  element++;
}

console.log(array);// [1, 3, 2, [5], [4]]

说明: Inner循环将数组的第一个元素与以最高索引处的元素开头的所有其他元素进行比较。向第一个元素递减,从数组中拼接出一个副本。

当内循环完成时,外循环递增到下一个元素进行比较,并重置数组的新长度。

答案 34 :(得分:1)

const numbers = [1, 1, 2, 3, 4, 4];

function unique(array) {
  return array.reduce((a,b) => {
    let isIn = a.find(element => {
        return element === b;
    });
    if(!isIn){
      a.push(b);
    }
    return a;
  },[]);
}

let ret = unique(numbers); // [1, 2, 3, 4]

使用reduce和find的方式。

答案 35 :(得分:1)

function arrayDuplicateRemove(arr){
    var c = 0;
    var tempArray = [];
    console.log(arr);
    arr.sort();
    console.log(arr);
    for (var i = arr.length - 1; i >= 0; i--) {
        if(arr[i] != tempArray[c-1]){
            tempArray.push(arr[i])
            c++;
        }
    };
    console.log(tempArray);
    tempArray.sort();
    console.log(tempArray);
}

答案 36 :(得分:1)

以下脚本返回仅包含唯一值的新数组。它适用于字符串和数字。不需要额外的库只有vanilla JS。

浏览器支持:

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

https://jsfiddle.net/fzmcgcxv/3/

var duplicates = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl","Mike","Mike","Nancy","Carl"]; 
var unique = duplicates.filter(function(elem, pos) {
    return duplicates.indexOf(elem) == pos;
  }); 
alert(unique);

答案 37 :(得分:0)

aLinks是一个简单的JavaScript数组对象。如果在索引显示删除重复记录的元素之前存在任何元素。我重复取消所有重复项。一个通道阵列取消更多记录。

var srt_ = 0;
var pos_ = 0;
do {
    var srt_ = 0;
    for (var i in aLinks) {
        pos_ = aLinks.indexOf(aLinks[i].valueOf(), 0);
        if (pos_ < i) {
            delete aLinks[i];
            srt_++;
        }
    }
} while (srt_ != 0);

答案 38 :(得分:0)

如果您不想包含整个库,可以使用此方法添加任何阵列可以使用的方法:

Array.prototype.uniq = function uniq() {
  return this.reduce(function(accum, cur) { 
    if (accum.indexOf(cur) === -1) accum.push(cur); 
    return accum; 
  }, [] );
}

["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"].uniq()

答案 39 :(得分:0)

删除字符串重复项的最简单方法是使用关联数组,然后遍历关联数组以使列表/数组返回。

如下所示:

var toHash = [];
var toList = [];

// add from ur data list to hash
$(data.pointsToList).each(function(index, Element) {
    toHash[Element.nameTo]= Element.nameTo;
});

// now convert hash to array
// don't forget the "hasownproperty" else u will get random results 
for (var key in toHash)  {
    if (toHash.hasOwnProperty(key)) { 
      toList.push(toHash[key]);
   }
}

Voila,现在重复了!

答案 40 :(得分:0)

这是另一种使用jQuery的方法,

function uniqueArray(array){
  if ($.isArray(array)){
    var dupes = {}; var len, i;
    for (i=0,len=array.length;i<len;i++){
      var test = array[i].toString();
      if (dupes[test]) { array.splice(i,1); len--; i--; } else { dupes[test] = true; }
    }
  } 
  else {
    if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');
      return(array);
  }
  return(array);
}

作者: William Skidmore

答案 41 :(得分:0)

此解决方案使用新数组和函数内的对象映射。它所做的就是循环遍历原始数组,并将每个整数添加到对象map中。如果在循环遍历原始数组时它会遇到重复,

=TIMEVALUE(SUBSTITUTE(MID(A1,12,8),".",":"))

捕获这个,因为对象上已经有一个具有相同数字的键属性。因此,跳过该数字并且不允许将其推入新数组中。

`if (!unique[int])`

答案 42 :(得分:0)

删除副本的最简单方法是执行for循环并比较不相同的元素并将它们推入新数组

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

 var removeDublicate = function(arr){
 var result = []
 var sort_arr = arr.sort() //=> optional
 for (var i = 0; i < arr.length; i++) {
        if(arr[ i + 1] !== arr[i] ){
            result.push(arr[i])
        }
 };
  return result
}  
console.log(removeDublicate(array))
==>  ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

答案 43 :(得分:0)

var uniqueCompnies = function(companyArray) {
    var arrayUniqueCompnies = [],
        found, x, y;

    for (x = 0; x < companyArray.length; x++) {
        found = undefined;
        for (y = 0; y < arrayUniqueCompnies.length; y++) {
            if (companyArray[x] === arrayUniqueCompnies[y]) {
                found = true;
                break;
            }
        }

        if ( ! found) {
            arrayUniqueCompnies.push(companyArray[x]);
        }
    }

    return arrayUniqueCompnies;
}

var arr = [
    "Adobe Systems Incorporated",
    "IBX",
    "IBX",
    "BlackRock, Inc.",
    "BlackRock, Inc.",
];

答案 44 :(得分:0)

我知道我有点晚了,但这是使用jinqJs

的另一种选择

See Fiddle

var result = jinqJs().from(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]).distinct().select();

答案 45 :(得分:0)

使用lodash快速轻松 - var array = ["12346","12347","12348","12349","12349"]; console.log(_.uniqWith(array,_.isEqual));

答案 46 :(得分:0)

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

for(var i=0;i<lines.length;i++)
{
    if(uniqueNames.indexOf(lines[i]) == -1)
        uniqueNames.push(lines[i]);
}
if(uniqueNames.indexOf(uniqueNames[uniqueNames.length-1])!= -1)
    uniqueNames.pop();
for(var i=0;i<uniqueNames.length;i++)
{
    document.write(uniqueNames[i]);
      document.write("<br/>");
}

答案 47 :(得分:0)

function removeDuplicates (array) {
  var sorted = array.slice().sort()
  var result = []

  sorted.forEach((item, index) => {
    if (sorted[index + 1] !== item) {
      result.push(item)
    }
  })
  return result
}

答案 48 :(得分:0)

Vanilla JS解决方案,复杂度为O(n)(此问题可能最快)。如果需要,修改hashFunction以区分对象(例如1和&#34; 1&#34;)。第一种解决方案避免了隐藏循环(在Array提供的函数中很常见)。

var dedupe = function(a) 
{
    var hash={},ret=[];
    var hashFunction = function(v) { return ""+v; };
    var collect = function(h)
    {
        if(hash.hasOwnProperty(hashFunction(h)) == false) // O(1)
        {
            hash[hashFunction(h)]=1;
            ret.push(h); // should be O(1) for Arrays
            return;
        }
    };

    for(var i=0; i<a.length; i++) // this is a loop: O(n)
        collect(a[i]);
    //OR: a.forEach(collect); // this is a loop: O(n)

    return ret;
}

var dedupe = function(a) 
{
    var hash={};
    var isdupe = function(h)
    {
        if(hash.hasOwnProperty(h) == false) // O(1)
        {
            hash[h]=1;
            return true;
        }

        return false;
    };

    return a.filter(isdupe); // this is a loop: O(n)
}

答案 49 :(得分:0)

如果您自己创建阵列,则可以在插入数据时通过检查来节省自己的循环和额外的唯一过滤器;

var values = [];
$.each(collection, function() {
    var x = $(this).value;
    if (!$.inArray(x, values)) {
        values.push(x);
    }
});

答案 50 :(得分:0)

function removeDuplicates(inputArray) {
            var outputArray=new Array();

            if(inputArray.length>0){
                jQuery.each(inputArray, function(index, value) {
                    if(jQuery.inArray(value, outputArray) == -1){
                        outputArray.push(value);
                    }
                });
            }           
            return outputArray;
        }

答案 51 :(得分:0)

var duplicates = function(arr){
     var sorted = arr.sort();
   var dup = [];
   for(var i=0; i<sorted.length; i++){
        var rest  = sorted.slice(i+1); //slice the rest of array
       if(rest.indexOf(sorted[i]) > -1){//do indexOf
            if(dup.indexOf(sorted[i]) == -1)    
         dup.push(sorted[i]);//store it in another arr
      }
   }
   console.log(dup);
}

duplicates(["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]);

答案 52 :(得分:-5)

ES2015,1-liner,与map链接良好,但仅适用于整数:

[1, 4, 1].sort().filter((current, next) => current !== next)
  

[1,4]

相关问题