从JS数组中删除重复的值

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

  • 获取数组中的所有唯一值(删除重复项)57个答案

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

    “聪明”但天真的方式

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

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

    使用过滤器回调的第三个(“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) {
        var seen = new Set();
        return a.filter(item => {
            var k = key(item);
            return seen.has(k) ? false : seen.add(k);
        });
    }
    

    (有些人喜欢!seen.has(k) && seen.add(k)而不是seen.has(k) ? false : seen.add(k) )。

    图书馆

    下划线和Lo-Dash都提供了uniq方法。 他们的算法与上面的第一个片段基本相似,归结为:

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

    这是二次的,但是还有很多其他的好处,比如包装本地indexOf ,通过键iteratee (用他们的说法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)

    厌倦了用for-loops或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和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)
    
    链接地址: http://www.djcxy.com/p/19261.html

    上一篇: Remove duplicate values from JS array

    下一篇: How to remove item from array by value?