从JS数组中删除重复的值[duplicate]

2020/09/16 17:13 · javascript ·  · 0评论

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

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

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

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

类似的问题:

快速而肮脏的使用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);
});

TL; DR

使用Set构造函数和spread语法

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

“聪明”但幼稚的方式

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

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

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

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}])将返回just [{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);
    });
}

排序 优衣库

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

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

图书馆

无论下划线罗短跑提供uniq方法。他们的算法基本上类似于上面的第一个代码片段,归结为:

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

这是二次方的,但是还有许多其他好处,例如包装native 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核心人员做得很好!)

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

厌倦了使用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中,您可以使用Sets and Spread来删除所有重复项,并且操作起来非常简单和高效:

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)

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:使用新的Set数据结构(顺序安全)

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

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

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

使用Underscore.js

它是一个包含用于操纵数组的函数的库。

这是与jQuery的晚礼服和Backbone.js的吊带一起使用的纽带。

_.uniq

_.uniq(array, [isSorted], [iterator]) 别名: unique

生成
数组的无重复版本,使用===测试对象是否相等。如果您事先知道该数组已排序,则为isSorted传递
true将运行更快的算法。如果要基于转换计算唯一项,请传递迭代器
函数。

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

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

注意:Lo-Dash下划线竞争对手)还提供了类似的.uniq实现。

您可以借助方法的第二个-index-参数简单地在JavaScript中完成此操作filter

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)

一条线:

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

使用Array.filter()这样的

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

在ES6中可以将其缩短为

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

是一个很好的解释Array.filter()

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

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

就像我在其他示例中看到的那样,不需要reduce函数slice也不indexOf在reduce函数之内!不过,将其与过滤器函数一起使用是有意义的:

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

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

Array.from(new Set(vals))

甚至使用价差运算符

[...new Set(vals)]

干杯!

最高答案的复杂度为O(n²),但这可以O(n)通过将对象用作哈希来完成:

function getDistinctArray(arr) {
    var dups = {};
    return arr.filter(function(el) {
        var hash = el.valueOf();
        var isDup = dups[hash];
        dups[hash] = true;
        return !isDup;
    });
}

这将适用于字符串,数字和日期。如果您的数组包含对象,则上述解决方案将不起作用,因为当被强制为字符串时,它们都将具有"[object Object]"(或类似值)的值,并且不适合作为查找值。您可以O(n)通过在对象本身上设置标志来获得对象的实现:

function getDistinctObjArray(arr) {
    var distinctArr = arr.filter(function(el) {
        var isDup = el.inArray;
        el.inArray = true;
        return !isDup;
    });
    distinctArr.forEach(function(el) {
        delete el.inArray;
    });
    return distinctArr;
}

2019编辑:现代版本的JavaScript使这个问题更容易解决。Set无论您的数组包含对象,字符串,数字还是任何其他类型,都可以使用using

function getDistinctArray(arr) {
    return [...new Set(arr)];
}

实现是如此简单,不再需要定义功能。

解决方案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]

性能

当我测试两种实现(带有和不带有Set)的chrome性能时,我发现带有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");

去这个:

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

现在uniqueArray不包含重复项。

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

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

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

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set

我在其他一些问题上做了过比较的去除假人的比较,但是注意到这是我也想在这里分享的真实地方。

我相信这是最好的方法

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

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

  • 在firefox v47中,red&lut:14.85ms与filter&indexOf:2836ms
  • 在chrome v51中reduce&lut:23.90ms vs filter&indexOf:1066ms

好吧,到目前为止很好。但是,这次让我们以ES6样式正确进行操作。看起来很酷..!但是到目前为止,它如何与功能强大的lut解决方案相媲美对我来说还是一个谜。首先查看代码,然后对其进行基准测试。

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

哇,真短..!但是性能如何呢?这很漂亮...由于过滤器/ indexOf的重量过大,现在我可以测试范围为0..99999的1M正整数随机项目数组,以从10次连续测试中获得平均值。我可以说这次是一场真正的比赛。自己查看结果:)

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

您将使用哪一个?嗯,不是那么快...!不要被欺骗。地图处于位移状态。现在看...在上述所有情况下,我们用范围<n的数字填充大小为n的数组。我的意思是我们有一个大小为100的数组,并且我们填充了随机数0..9,因此存在一定的重复项,并且“几乎”肯定每个数字都有重复项。如果我们用随机数0..9999填充大小为100的数组,该怎么办。现在让我们看看地图在家里玩。这次是一个100K项的数组,但随机数范围是0..100M。我们将进行100次连续测试以平均结果。好,让我们看看下注吧!<-没有错字

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

现在,这是Map()壮观的复兴。可能现在您可以在想要删除重复对象时做出更好的决定。

好吧,我们现在都很高兴。但是主角总是在掌声中排在最后。我敢肯定,有些人想知道Set对象会做什么。既然我们对ES6开放,并且我们知道Map是以前的比赛的赢家,那么让我们比较一下Map与Set作为最终决赛。这次是典型的皇马对巴塞罗那的比赛……还是?让我们看看谁将赢得经典奖:)

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

哇..男人..!出乎意料的是,它根本没有成为经典。更像是巴塞罗那足球俱乐部对阵奥萨苏纳(:)

以下内容比列出的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

在ECMAScript 6(又名ECMAScript 2015)中,Set可用于过滤出重复项。然后可以使用散布运算符将其转换回数组

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

这是该问题的简单答案。

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

一种简单但有效的技术是将该filter方法与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>';

另请参见此Fiddle

因此,选项为:

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]

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

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)

在此处输入图片说明

这对于在任何地方(甚至在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"]

除了是比当前答案更简单,更简洁的解决方案(减去具有前瞻性的ES6解决方案)之外,我进行了性能测试,并且速度也更快:

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

一个警告:在IE9中添加了Array.lastIndexOf(),因此,如果您需要降低此值,则需要查找其他地方。

通用功能方法

这是ES2015的一种通用且严格起作用的方法:

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

我们可以轻松地uniques 派生unqiueBy或使用更快的实现Set

const unqiue = uniqueBy(eq);

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

这种方法的好处:

  • 通过使用单独的比较器功能的通用解决方案
  • 声明式和简洁的实现
  • 重用其他小的通用功能

性能考量

uniqueBy 虽然没有像使用循环这样的命令式实现那样快,但是由于其通用性,它的表达方式更加丰富。

如果您确定uniqueBy是造成应用程序具体性能下降的原因,请用优化的代码代替。也就是说,首先以功能性的声明方式编写代码。此后,如果遇到性能问题,请尝试在引起问题的位置优化代码。

内存消耗和垃圾回收

uniqueBy利用push(x) (acc)隐藏在其体内的突变()。它重复使用累加器,而不是在每次迭代后将其丢弃。这样可以减少内存消耗和GC压力。由于此副作用包含在函数内部,因此外部的所有内容都保持纯净。

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

如果您有机会使用

D3.js

你可以做

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

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

$(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);
});

略微修改了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);
    });
}

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

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

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

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

这可能是从阵列中永久删除重复项的最快方法之一,其速度是
此处大多数功能的10倍。&在野生动物园中的速度是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

如果您看不懂上面的代码,请阅读一本javascript书籍,或以下有关较短代码的说明。https://stackoverflow.com/a/21353032/2450730

本文地址:http://javascript.askforanswer.com/congjsshuzuzhongshanchuzhongfudezhiduplicate.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!