【问题标题】:Remove duplicate values from JS array [duplicate]从 JS 数组中删除重复值 [重复]
【发布时间】:2021-07-29 03:37:43
【问题描述】:

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

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

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

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

类似问题:

【问题讨论】:

  • _.uniq(peoplenames) 解决了这个问题lodash.com/docs#uniq
  • @ConnorLeech 使用 lodash 很容易,但没有经过优化
  • 最简单的方法(在我看来)是使用 Set 对象,它可以让您存储任何类型的唯一值。换句话说,Set 会自动为我们移除重复项。 const names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"]; let unique = [...new Set(names)]; console.log(unique); // 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl'
  • 世界上有太多的麦克 - 为什么不删除它们?南希对此有所了解。
  • 在我的解决方案中,我在过滤之前对数据进行排序:` const result = data.sort().filter((v, idx, t) => idx==0 || v != t[ idx-1]);

标签: javascript arrays duplicates unique


【解决方案1】:

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

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

【讨论】:

  • 想解释一下它如何消除欺骗?
  • @web_dev:它没有!我已经更正了之前破坏代码的编辑。希望它现在更有意义。感谢您的提问!
  • 不幸的是,如果这是一个大数组,则性能很差——arr.indexOf 为 O(n),这使得该算法为 O(n^2)
  • 正如@CaseyKuball 建议的那样,这个解决方案实际上非常慢 - 请参阅*.com/questions/67424599/…
  • 伟大的 SVG 图标 :) 你给了我灵感,也是一个很好的答案。
【解决方案2】:

TL;DR

使用Set 构造函数和spread syntax

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

“聪明”但幼稚的方式

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

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

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

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

排序 |独特的

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

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 方法。他们的算法与上面的第一个sn-p基本相似,归结为:

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

这也是第一个 sn-p 的变体。

性能

函数调用在 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;
}

这段丑陋的代码与上面的 sn-p #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

【讨论】:

  • filter 和 indexOf 已在 ECMAScript 5 中引入,因此这在旧 IE 版本 (
  • @RoderickObrist 如果您希望您的页面在旧版浏览器中工作,您可以这样做
  • 这是O(n^2) 解决方案,在大型阵列中运行速度可能非常慢...
  • 试试这个数组:["toString", "valueOf", "failed"]toStringvalueOf 被完全剥离。使用Object.create(null) 而不是{}
  • 有谁知道 Set 转换解决方案与其他解决方案相比有多快?
【解决方案3】:
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/>");
}

【讨论】:

  • 您的代码运行良好。但代码“uniqueNames.pop()”无缘无故地删除了最后一个数组元素。它使“Carl”没有从数组中列出。
【解决方案4】:

最佳答案的复杂度为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 都会起作用。

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

实现如此简单,不再需要定义函数。

【讨论】:

  • 您是否考虑过您的方法对性能的影响?
  • @Tushar - 您的要点给出了 404。没有排序算法具有 O(n) 复杂性。排序不会更快。
  • @Tushar - 该数组中没有实际的重复项。如果要从数组中删除与数组中其他对象具有完全相同属性和值的对象,则需要编写自定义相等检查函数来支持它。
  • @Tushar - 此页面上的任何答案都不会从your gist 中的此类数组中删除任何重复项。
  • 请注意,IE 参加 Set 聚会迟到了
【解决方案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"]

【讨论】:

    【解决方案6】:

    解决方案 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");

    【讨论】:

    • 赞成使用 Set。虽然我不知道性能比较
    • 我在某处读到 Array 比 Set 快(整体性能),但是当我在 chrome 中测试时,使用 Set 的实现要快得多!查看编辑后的答案:)
    • 更好的做法是使用 Object.defineProperty(Array.prototype,"unique".. 而不是 Array.prototype.unique = ... 在此处查看更多信息*.com/questions/10105824/…
    • Set 方法似乎不适用于 Node.js 中的我。 new Set([5,5]) 在某些情况下似乎返回 [5,5]。我和你一样困惑。编辑:我发现发生了什么。 new Set([new Number(5), new Number(5)]) 返回 [5,5]。显然,如果我用 new 实例化这两个数字 5,Node 会认为它们是不同的......老实说,这是我见过的最愚蠢的事情。
    • @Demonblack 这是一个有效的问题。 x=new Number(5) 和另一个 y=new Number(5) 将是两个不同的对象,与 var x=5 和 var y=5 相反。 new 关键字将创建一个新对象。我知道这个解释很明显,但我只知道这些:)
    【解决方案7】:

    以下方法比列出的 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

    【讨论】:

    • 我在修订版 4 中添加了更快的版本。请查看!
    • 测试好像没有使用数组???我添加了(又一个)一个在不同浏览器上似乎始终快速的(参见jsperf.com/remove-duplicate-array-tests/10):for (var n = array.length, result = [array[n--]], i; n-- ;) { i = 数组[n]; if (!(i in result)) result.push(i); } 返回结果;
    【解决方案8】:

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

    【讨论】:

    • 你能详细说明你在这里做了什么吗? :-)
    • 太棒了!如果您将其添加到您的答案中,它将对用户有所帮助。
    • 当数组是数组数组时不起作用
    • 不适用于区分大小写的数组
    【解决方案9】:
    for (i=0; i<originalArray.length; i++) {  
        if (!newArray.includes(originalArray[i])) {
            newArray.push(originalArray[i]); 
        }
    }
    

    【讨论】:

    • 喜欢香草js。谢谢
    【解决方案10】:

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

    【讨论】:

    • 这只适用于包含原语的数组?
    • 是的,你是对的@frozen
    • 这个a.indexOf(v)==i应该是a.indexOf(v) === a.lastIndexOf(v)
    • @Hitmands 你从右边比较,我从左边比较。没有别的。
    • 在不需要a 变量的情况下也可以工作,因为数组是filter 的第三个参数:[1/0, 2,1/0,2,3].filter((v,i,a) =&gt; a.indexOf(v) === i)(请注意,它也适用于Infinity ☺)
    【解决方案11】:

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

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

    【讨论】:

    • 你在reduce方法后添加的空数组的目的是什么?
    【解决方案12】:

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

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

    [1, 4]

    【讨论】:

    • 这适用于任何东西,但只删除顺序重复。例如[1,1,2,2,3,3] -> [1,2,3][1,2,3,1,2,3] -> [1,2,3,1,2,3]
    • @Kroltan 这实际上不是顺序重复的问题,但理解传递给filter 的内容是一个大问题:它是(value, index) 而不是(current, next),所以它适用于[1,4,1]但不适用于[2,4,2]...
    • @Xenos 你是对的!我浏览的太快了xD
    • 我认为这种方法很好,也可以轻松地用于其他类型的数组,只需稍作修改:["1", "4", "1"].sort().filter((value, index, array) =&gt; value !== array[index + 1])
    【解决方案13】:
    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.",
    ];
    

    【讨论】:

    • 请格式化整篇文章
    【解决方案14】:

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

    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)

    【讨论】:

      【解决方案15】:

      一行:

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

      【讨论】:

      • 最佳答案,如果您使用的是 ES6
      【解决方案16】:

      虽然 ES6 解决方案是最好的,但我很困惑如何没有人展示以下解决方案:

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

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

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

      【讨论】:

        【解决方案17】:
        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的方式。

        【讨论】:

          【解决方案18】:

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

          `if (!unique[int])`
          

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

              function removeRepeats(ints) {
                var unique = {}
                var newInts = []
          
                for (var i = 0; i < ints.length; i++) {
                  var int = ints[i]
          
                  if (!unique[int]) {
                    unique[int] = 1
                    newInts.push(int)
                  }
                }
                return newInts
              }
          
              var example = [100, 100, 100, 100, 500]
              console.log(removeRepeats(example)) // prints [100, 500]
          

          【讨论】:

            【解决方案19】:

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

            【讨论】:

            • 天才!而且,例如,如果您想要重复的,(而不是删除它们)您所要做的就是将 this.indexOf(value) == index 替换为 this.indexOf(value, index+1) &gt; 0 谢谢!
            • 您甚至可以将其恢复到单个“过滤器”行:filterData = data.filter((v, i) =&gt; (data.indexOf(v) == i) );
            • 上次打扰了!抱歉...拿起我的第一个答案,在 2 行中,您可以得到一个 JSON var JSON_dupCounter = {}; 以及重复的次数以及重复次数:data.filter((testItem, index) =&gt; (data.indexOf(testItem, index + 1) &gt; 0)).forEach((found_duplicated) =&gt; (JSON_dupCounter[found_duplicated] = (JSON_dupCounter [found_duplicated] || 1) + 1));
            • 这只适用于基元数组?
            • @frozen :如果适用于所有== 可用于确定相等性的东西。所以,如果你正在处理例如。数组、对象或函数,过滤器仅适用于引用相同数组、对象或函数的不同条目 (see demo)。如果您想根据 different criteria 确定相等性,则需要在过滤器中包含这些条件。
            【解决方案20】:

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

            【讨论】:

              【解决方案21】:

              所以选项是:

              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]
              

              【讨论】:

                【解决方案22】:

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

                【讨论】:

                  【解决方案23】:

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

                  【讨论】:

                  • 不介意为那些不使用它的人提供非 jquery 答案
                  • 由于这已被一位知名人士恢复为原始的inArray 解决方案,所以我要再次提及:此解决方案是 O(n^2),因此效率低下。
                  • 我真的希望在 2020 年我们可以开始贬值 jQuery 和其他更过时的答案...... * 开始在这里显示一些年龄......
                  • 我同意@NickSteele,但如果您查看选票而不是接受的答案,我发现它确实会随着时间的推移自然发生。随着旧的弃用答案被否决,最佳答案将被排在首位
                  • 让 uniqueNames = names.filter((item, pos ,self) => self.indexOf(item) == pos);
                  【解决方案24】:

                  迄今为止我遇到的最简单的一个。在 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

                  【讨论】:

                  • 对于 Mac 用户,即使这是一个 ES6 函数,它也可以在 macOS 10.11.6 El Capitan 中使用,使用脚本编辑器。
                  【解决方案25】:
                  function removeDuplicates (array) {
                    var sorted = array.slice().sort()
                    var result = []
                  
                    sorted.forEach((item, index) => {
                      if (sorted[index + 1] !== item) {
                        result.push(item)
                      }
                    })
                    return result
                  }
                  

                  【讨论】:

                    【解决方案26】:

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

                    【讨论】:

                      【解决方案27】:

                      去这个:

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

                      现在 uniqueArray 不包含重复项。

                      【讨论】:

                      • 我认为,最好的!
                      【解决方案28】:

                      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 Data-Structure,它允许您存储任何类型的值。 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"]
                      

                      【讨论】:

                      • 在较新的浏览器中,您甚至可以使用var c = Object.keys(b)。应该注意的是,这种方法只适用于字符串,但没关系,这就是原始问题所要求的。
                      • 还应该注意,您可能会丢失数组的顺序,因为对象不会按顺序保持其属性。
                      • @JuanMendes 我创建了一个订单安全版本,如果之前没有看到过该值,它会简单地复制到新数组。
                      • obj[arr[i]] = true; 这一行发生了什么??
                      • @kittu,即获取数组的ith 元素,并将其放入对象中(用作集合)。键是元素,值是true,这完全是任意的,因为我们只关心对象的键。
                      【解决方案29】:

                      通用函数方法

                      这是 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,或者使用更快的实现,利用Sets:

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

                      这种方法的好处:

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

                      性能注意事项

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

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

                      内存消耗和垃圾回收

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

                      【讨论】:

                        【解决方案30】:

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

                        干杯!

                        【讨论】:

                        • Set 对于那些习惯使用 python 的人来说非常棒且非常直观。太糟糕了,他们没有那些很棒的(联合、相交、差异)方法。
                        • 我使用了使用set 机制的简单的一行代码。这是针对自定义自动化任务的,所以我对在最新版本的 Chrome(在 jsfiddle 内)中使用它并不持怀疑态度。但是,我仍然想知道对数组进行重复数据删除的最短所有浏览器兼容方法。
                        • 集合是新规范的一部分,你应该使用 sort/reduce 组合来确保跨浏览器的兼容性@AlexanderDixon
                        • .reduce() 不兼容跨浏览器,因为我必须应用 poly-fill。不过,我很感谢你的回应。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…