我有两个JavaScript数组:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

我希望输出为:

var array3 = ["Vijendra","Singh","Shakya"];

输出数组应删除重复的单词。

如何在JavaScript中合并两个数组,以便从每个数组中只获得唯一的项目,其顺序与它们插入原始数组的顺序相同?


当前回答

/***对仅保留唯一值的数组进行重复数据消除。*使用哈希表(js对象)过滤重复项。*保持数组元素的顺序。*该算法对于大型阵列(线性时间)特别有效。*/函数数组UniqueFast(arr){var seen={};var结果=[];变量i,长度=arr.length;对于(i=0;i<len;i++){var项目=arr[i];//哈希表查找if(!seed[item]){result.push(项);seed[项目]=真;}}返回结果;}/////测试var array1=[“Vijendra”,“Singh”];var array2=[“Singh”,“Shakya”];var result=arrayUniqueFast(array1.concat(array2));document.write('<br>result:'+result);

有关阵列重复数据消除的其他方法,请参阅我的基准测试:https://jsperf.com/de-duplicate-an-array-keeping-only-unique-values

其他回答

构建一个测试人员来检查一些面向性能的答案的速度。请随意添加更多内容。到目前为止,Set是最简单和最快的选项(随着记录数量的增加,它的边距会更大),至少对于简单的number类型来说是如此。

常量记录=10000,//每个阵列的最大记录数max_int=100,//每个数组的最大整数值dup_rate=.5//复制率让perf={},//性能记录器,ts=0,te=0,array1=[],//初始化数组array2=[],array1b=[],array2b=[],a=[];//填充随机化数组for(设i=0;i<记录;i++){设r=Math.random(),n=r*max_int;如果(Math.random()<.5){array1.push(n);r<dup_rate&&array2.push(n);}其他{阵列2.push(n);r<dup_rate&&array1.push(n);}}//缺少rfdc的简单深度副本,以防有人想要使用更复杂的数据类型进行测试array1b=JSON.parse(JSON.stringify(array1));array2b=JSON.parse(JSON.stringfy(array2));console.log('数组1中的记录:',array1.length,array1b.length);console.log('数组2中的记录:',array2.length,array2b.length);//试验方法1(jsperf per@Pitouli)ts=performance.now();for(设i=0;i<array2.length;i++)如果(array1.indexOf(array2[i])==-1)array1.push(array2[i])//修改数组1te=performance.now();perf.m1=te-ts;console.log('方法1合并',array1.length,'记录在:',perf.m1);array1=JSON.parse(JSON.stringify(array1b))//重置阵列1//测试方法2(经典的Each)ts=performance.now();array2.forEach(v=>array1.includes(v)?null:array1.push(v))//修改数组1te=performance.now();perf.m2=te-ts;console.log('方法2合并',array1.length,'记录在:',perf.m2中);//测试方法3(最简单的本机选项)ts=performance.now();a=[…新集合([…array1,…array2])]//不修改源阵列te=performance.now();perf.m3=te-ts;console.log('方法3合并',a.length,'记录在:',perf.m3);//测试方法4(选定答案)ts=performance.now();a=阵列1.concat(阵列2)//不修改源阵列for(设i=0;i<a.length;++i){for(设j=i+1;j<a.length;++j){如果(a[i]===a[j])a.接头(j-,1);}}te=performance.now();perf.m4=te-ts;console.log('Method 4 merged',a.length,'records in:',perf.m4);//试验方法5(@Kamil Kielczewski)ts=performance.now();函数K(arr1,arr2){设r=[],h={};而(arr1.length){设e=arr1.shift()//修改数组1如果(!h[e])h[e]=1&&r.push(e);}而(arr2.长度){设e=arr2.shift()//修改数组2如果(!h[e])h[e]=1&&r.push(e);}返回r;}a=K(阵列1,阵列2);te=performance.now();perf.m5=te-ts;console.log('Method 5 merged',a.length,'records in:',perf.m4);array1=JSON.parse(JSON.stringify(array1b))//重置阵列1array2=JSON.parse(JSON.stringfy(array2b))//重置阵列2for(设i=1;i<6;i++){console.log('方法:',i,'速度为',(perf[m'+i]/perf.m1*100).toFixed(2),'方法1的%');}

ES2015的功能方法

按照函数方法,两个数组的联合只是concat和filter的组合。为了提供最佳性能,我们使用本机Set数据类型,该类型针对属性查找进行了优化。

无论如何,结合联合函数的关键问题是如何处理重复项。以下排列是可能的:

Array A      + Array B

[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

前两种排列很容易用一个函数处理。然而,后两个更复杂,因为只要依赖Set查找,就无法处理它们。由于切换到普通的旧Object属性查找会严重影响性能,因此下面的实现只会忽略第三个和第四个排列。你必须构建一个单独的union版本来支持它们。


//小型、可重复使用的辅助功能常量comp=f=>g=>x=>f(g(x));常量应用=f=>a=>f(a);常量flip=f=>b=>a=>f(a)(b);常量concat=xs=>y=>xs.contat(y);const afrom=应用(Array.from);const createSet=xs=>新集合(xs);常量过滤器=f=>xs=>xs.filter(apply(f));//重复数据消除常量重复数据删除=comp(afrom)(createSet);//实际联合函数常量并集=xs=>ys=>{const zs=创建集(xs);返回凹面(xs)(滤波器(x=>zs.has(x)? 假的:zs.add(x))(ys));}//模拟数据常量xs=[1,2,2,3,4,5];常量=[0,1,2,3,3,4,5,6,6];//我们来了console.log(“unique/unique”,union(重复数据消除(xs))(ys));console.log(“重复/唯一”,union(xs)(ys));

从这里开始,实现unionn函数变得很简单,它接受任意数量的数组(灵感来自naomik的评论):

//小型、可重复使用的辅助功能常量未修正=f=>(a,b)=>f(a)(b);常量foldl=f=>acc=>xs=>xs.reduce(uncurry(f),acc);常量应用=f=>a=>f(a);常量flip=f=>b=>a=>f(a)(b);常量concat=xs=>y=>xs.contat(y);const createSet=xs=>新集合(xs);常量过滤器=f=>xs=>xs.filter(apply(f));//工会和工会常量并集=xs=>ys=>{const zs=创建集(xs);返回凹面(xs)(滤波器(x=>zs.has(x)? 假的:zs.add(x))(ys));}常量unionn=(头,…尾)=>foldl(联合)(头)(尾);//模拟数据常量xs=[1,2,2,3,4,5];常量=[0,1,2,3,3,4,5,6,6];常数zs=[0,1,2,3,4,5,6,7,8,9];//我们来了console.log(unionn(xs,ys,zs));

事实证明unionn只是foldl(又名Array.protocol.reduce),它将union作为其缩减器。注意:由于实现没有使用额外的累加器,所以当您在没有参数的情况下应用它时,它会抛出错误。

看起来接受的答案是我测试中最慢的;

注意,我正在按Key合并2个对象数组

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button type='button' onclick='doit()'>do it</button>
<script>
function doit(){
    var items = [];
    var items2 = [];
    var itemskeys = {};
    for(var i = 0; i < 10000; i++){
        items.push({K:i, C:"123"});
        itemskeys[i] = i;
    }

    for(var i = 9000; i < 11000; i++){
        items2.push({K:i, C:"123"});
    }

    console.time('merge');
    var res = items.slice(0);

    //method1();
    method0();
    //method2();

    console.log(res.length);
    console.timeEnd('merge');

    function method0(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;
            if(itemskeys[k] == null){
                itemskeys[i] = res.length;
                res.push(items2[i]);
            }
        }
    }

    function method1(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;

            for(var j = 0; j < items.length; j++){
                if(items[j].K == k){
                    isok = 0;
                    break;
                }
            }

            if(isok) res.push(items2[i]);
        }  
    }

    function method2(){
        res = res.concat(items2);
        for(var i = 0; i < res.length; ++i) {
            for(var j = i+1; j < res.length; ++j) {
                if(res[i].K === res[j].K)
                    res.splice(j--, 1);
            }
        }
    }
}
</script>
</body>
</html>
Array.prototype.union = function (other_array) {
/* you can include a test to check whether other_array really is an array */
  other_array.forEach(function(v) { if(this.indexOf(v) === -1) {this.push(v);}}, this);    
}

只需使用Undercore.js的=>uniq即可实现:

array3 = _.uniq(array1.concat(array2))

console.log(array3)

它将印刷[“Vijendra”、“Singh”、“Shakya”]。