我有一个非常简单的JavaScript数组,其中可能包含重复项,也可能不包含重复项。
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
我需要删除重复项并将唯一值放入新数组中。
我可以指出我尝试过的所有代码,但是我认为这没用,因为它们不起作用。我也接受jQuery解决方案。
我有一个非常简单的JavaScript数组,其中可能包含重复项,也可能不包含重复项。
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
我需要删除重复项并将唯一值放入新数组中。
我可以指出我尝试过的所有代码,但是我认为这没用,因为它们不起作用。我也接受jQuery解决方案。
If by any chance you were using
D3.js
You could do
d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]
$(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);
});
这是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) );
我们可以轻松地unique
从s 派生unqiueBy
或使用更快的实现Set
:
const unqiue = uniqueBy(eq);
// const unique = xs => Array.from(new Set(xs));
这种方法的好处:
uniqueBy
虽然没有像使用循环这样的命令式实现那样快,但是由于其通用性,它的表达方式更加丰富。
如果您确定uniqueBy
是造成应用程序具体性能下降的原因,请用优化的代码代替。也就是说,首先以功能性的声明方式编写代码。此后,如果遇到性能问题,请尝试在引起问题的位置优化代码。
uniqueBy
利用push(x) (acc)
隐藏在其体内的突变()。它重复使用累加器,而不是在每次迭代后将其丢弃。这样可以减少内存消耗和GC压力。由于此副作用包含在函数内部,因此外部的所有内容都保持纯净。
除了是比当前答案更简单,更简洁的解决方案(减去具有前瞻性的ES6解决方案)之外,我进行了性能测试,并且速度也更快:
var uniqueArray = dupeArray.filter(function(item, i, self){
return self.lastIndexOf(item) == i;
});
一个警告:在IE9中添加了Array.lastIndexOf(),因此,如果您需要降低此值,则需要查找其他地方。
for (i=0; i<originalArray.length; i++) {
if (!newArray.includes(originalArray[i])) {
newArray.push(originalArray[i]);
}
}
这对于在任何地方(甚至在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"]
因此,选项为:
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)
以下内容比列出的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
这是对该问题的简单答案。
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]);
}
}
解决方案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(使用设置)
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");
到目前为止,我遇到的最简单的一个。在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 uniqueArray = duplicateArray.filter(function(elem, pos) {
return duplicateArray.indexOf(elem) == pos;
});
现在uniqueArray不包含重复项。
最高答案的复杂度为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)];
}
实现是如此简单,不再需要定义功能。
使用原生javascript函数从数组中删除重复项的最简洁方法是使用如下序列:
vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])
就像我在其他示例中看到的那样,没有必要slice
也没有indexOf
reduce函数!不过,将其与过滤器函数一起使用是有意义的:
vals.filter(function(v, i, a){ return i == a.indexOf(v) })
ES6(2015)的另一种已在少数浏览器上运行的方式是:
Array.from(new Set(vals))
甚至使用价差运算符:
[...new Set(vals)]
干杯!
它是一个包含用于操纵数组的函数的库。
这是与jQuery的晚礼服和Backbone.js的吊带一起使用的纽带。
_.uniq(array, [isSorted], [iterator])
别名: unique
产生数组的无重复版本,使用===测试对象的相等性。如果您事先知道该数组已排序,则为isSorted传递 true将运行更快的算法。如果要基于转换计算唯一项,请传递迭代器 函数。
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
alert(_.uniq(names, false));
使用数组过滤器和indexOf函数的单行版本:
arr = arr.filter (function (value, index, array) {
return array.indexOf (value) == index;
});
您可以在JavaScript中简单地借助方法的第二个-index-参数来实现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)
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"]
快速而肮脏的使用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);
});
https://jsfiddle.net/2w0k5tz8/
Loop through, remove duplicates, and create a clone array place holder because the array index will not be updated.
Loop backward for better performance ( your loop wont need to keep checking the length of your array)