首页 文章

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

提问于
浏览
969

这个问题在这里已有答案:

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

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

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

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

同类的问题:

30 回答

  • 4

    一条线:

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

    “聪明”,但天真的方式

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

    虽然简洁,但该算法对于大型阵列(二次时间)并不是特别有效 .

    Hashtables救援

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

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

    • 因为哈希键只能是Javascript中的字符串,所以此代码不区分数字和"numeric strings" . 也就是说, 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"回调应用于每个元素,并删除具有相同"keys"的元素 . 由于 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 ,它将删除物理上不同的对象,但"look"相同:

    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) {
        var seen = new Set();
        return a.filter(item => {
            var k = key(item);
            return seen.has(k) ? false : seen.add(k);
        });
    }
    

    Map

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

    它们也适用于非原始键 .

    图书馆

    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集按插入顺序迭代,因此此代码保留原始数组的顺序 .

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

    发电机

    "lazy",基于生成器的 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
    
  • 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;
    }
    
  • 388

    在任何地方(甚至在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"]
    
  • 32

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

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

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

  • 63

    拿到厌倦了用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)
    
  • 19

    This is probably one of the fastest way to remove permanently the duplicates from an array 比这里的大多数功能快10倍 . 在safari中快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)
    }
    

    如果你不能阅读上面的代码问,请阅读javascript书或这里有一些关于更短代码的解释 . https://stackoverflow.com/a/21353032/2450730

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

    像这样使用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);
    

    Here很好解释 Array.filter()

  • 10

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

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

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

  • 8

    去这个:

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

    现在uniqueArray不包含重复项 .

  • 3

    Vanilla JS: Remove duplicates using an Object like a 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: Remove duplicates by tracking already seen values (order-safe)

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

    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: Use the new Set data structure (order-safe)

    ECMAScript 6添加了新的 Set 数据结构,它允许您存储任何类型的值 . Set.values 按插入顺序返回元素 .

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

    Example usage:

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

    最简单的一个我到目前为止已经遇到过 . 在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

  • 13

    使用Underscore.js

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

    这与jQuery的礼服和Backbone.js的吊带相关 .

    _.uniq

    _.uniq(array,[isSorted],[iterator])别名:unique生成数组的无副本版本,使用===来测试对象相等性 . 如果您事先知道数组已排序,则为isSorted传递true将运行更快的算法 . 如果要基于转换计算唯一项,请传递迭代器函数 .

    Example

    var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
    
    alert(_.uniq(names, false));
    

    注意:Lo-Dashunderscore竞争对手)也提供了类似的.uniq实现 .

  • 9

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

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

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

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

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

    Array.from(new Set(vals))
    

    甚至使用spread operator

    [...new Set(vals)]
    

    干杯!

  • 14

    您可以使用 filter 方法的第二个 - index - 参数在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)
    
  • 69

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

    here is the simple method without any special libraries are special function,

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

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

    我相信这是最好的方法

    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)我很想看到这个缩小/查找表和filter / indexOf组合之间的基准比较(我选择Jeetendras非常好的实现https://stackoverflow.com/a/37441144/4543207) . 我准备一个100K项目数组,填充0-9999范围内的随机正整数,并删除重复项 . 我重复测试了10次,结果的平均值表明它们的性能不匹配 .

    • 在firefox v47中减少&lut:14.85ms vs filter&indexOf:2836ms

    • 在chrome v51中减少&lut:23.90ms vs filter&indexOf:1066ms

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

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

    你会用哪一个..?好吧不是那么快......!不要被欺骗 . Map 处于位移状态 . 现在看......在上述所有情况下,我们填充一个大小为n的数组,其数量为范围<n . 我的意思是我们有一个100的数组,我们填充随机数0..9所以有确定的重复和“几乎”肯定每个数字都有重复 . 如果我们用随机数0..9999填充大小为100的数组怎么样 . 现在让我们看看 Map 在家玩 . 这次是一个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进行比较 . 这次典型的皇马对阵巴塞罗那比赛......或者是这样?让我们看看谁将赢得el classico :)

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

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

  • 9

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

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

    通用功能方法

    以下是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) );
    

    我们可以很容易地从 unqiueBy 派生 unique 或使用更快的实现利用 Set

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

    这种方法的好处:

    通过使用单独的比较器功能

    • 泛型解决方案

    • 声明性和简洁的实现

    • 重用其他小型通用函数

    性能注意事项

    uniqueBy 不如使用循环的命令式实现快,但由于其通用性,它更具表现力 .

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

    内存消耗和垃圾收集

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

  • 37

    如果您有任何机会使用

    D3.js

    你可以做到

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

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

  • 7

    一种简单但有效的技术,是将 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 .

  • 48

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

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

    一个警告:在IE9中添加了Array.lastIndexOf(),所以如果你需要低于它,你需要寻找其他地方 .

  • 4

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

    Solution 2 (using Set)

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

    Test

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

    Performance

    当我测试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");
    
  • 3
    $(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);
    });
    
  • 289

    这是一个简单的问题答案 .

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

    最佳答案的复杂性为 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;
        });
    }
    

    这适用于字符串,数字和日期 . 如果您的数组包含复杂对象(即,它们必须与 === 进行比较),则上述解决方案将不起作用 . 您可以通过在对象本身上设置标志来获取对象的 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;
    }
    
  • 2460

    所以选项是:

    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]
    

相关问题