JavaScript에서 두 개의 배열을 병합하고 항목을 중복 제거하는 방법


1364

두 개의 JavaScript 배열이 있습니다.

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

출력을 원합니다.

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

출력 배열은 반복 된 단어를 제거해야합니다.

JavaScript에서 두 개의 배열을 병합하여 원래 배열에 삽입 된 순서와 동일한 순서로 각 배열에서 고유 한 항목 만 가져 오려면 어떻게합니까?


1
새 답변을 게시하기 전에이 질문에 대한 답변이 75 개 이상 있다고 생각하십시오. 귀하의 답변이 기존 답변에 속하지 않은 정보를 제공하는지 확인하십시오.
janniks

[... 새로운 세트 ([... [1, 2, 3], ... [2, 3, 4]]]] 결과 [1, 2, 3, 4]
Denis Giffeler

심층 병합을 다루는보다 일반적인 솔루션을 원한다면 대신 이 질문을 살펴보십시오 . 일부 답변은 배열도 포함합니다.
마틴 브라운

답변:


1661

중복을 제거하지 않고 배열을 병합하려면

ES5 버전 사용 Array.concat:

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

console.log(array1.concat(array2));

ES6 버전 사용 파괴

const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];

중복을 제거하는 '내장'방법이 없기 때문에 ( ECMA-262는 실제로이 기능을 사용 Array.forEach하는 것이 좋습니다) 수동으로 수행해야합니다.

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
};

그런 다음 사용하십시오.

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique(); 

이것은 또한 배열의 순서를 유지합니다 (즉, 정렬이 필요하지 않습니다).

많은 사람들이 프로토 타입 기능 보강 Array.prototypefor in루프 에 대해 짜증을 내고 있기 때문에 이를 사용하는 덜 침습적 인 방법은 다음과 같습니다.

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));

ES5를 사용할 수있는 브라우저로 작업 할 수있을만큼 운이 좋은 사람들은 다음 Object.defineProperty과 같이 사용할 수 있습니다 .

Object.defineProperty(Array.prototype, 'unique', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }

        return a;
    }
});

281
이 알고리즘은 O (n ^ 2)입니다.
Gumbo

7
하자 [a, b, c][x, b, d]배열 될 (따옴표를 가정). concat이 제공합니다 [a, b, c, x, b, d]. unique ()의 출력이 아닙니다 [a, c, x, b, d]. 내가 생각하는 순서를 유지하지 않습니다 - 나는 OP가 원하는 생각[a, b, c, x, d]
Amarghosh

89
OP는 그가 일하게 한 첫 번째 대답을 받아들이고 서명 한 것으로 보입니다. 우리는 여전히 서로의 솔루션을 비교하고, 결함을 찾아 내고, 결함을 찾고, 성능을 향상 시키며, 어느 곳에서나 호환되는지 확인합니다 ... stackoverflow의 아름다움 :-)
Amarghosh

6
나는 원래 이것을 투표했지만 내 마음을 바꿨다. Array.prototype에 프로토 타입을 할당하면 "for ... in"문이 손상됩니다. 따라서 가장 좋은 해결책은 아마도 이와 같은 기능을 사용하지만 프로토 타입으로 할당하지 않는 것입니다. 어떤 사람들은 어쨌든 배열 요소를 반복하기 위해 "for ... in"문을 사용해서는 안된다고 주장 할 수도 있지만, 사람들은 종종이 방법을 사용하여 최소한이 솔루션을주의해서 사용해야합니다.
코드 사령관

16
당신은 항상 사용해야 for ... inhasOwnProperty이 경우 프로토 타입 방법은 괜찮
mulllhausen

600

Underscore.js 또는 Lo-Dash를 사용하면 다음을 수행 할 수 있습니다.

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union


70
또는 아마도 API 호환 lodash 밑줄보다 낫습니다 .
Brian M. Hunt

3
@Ygg lodash 문서에서. " 하나 이상의 배열에있는 고유 한 값으로 구성된 새 배열을 순서대로 반환 합니다."
Richard Ayotte

4
underscore.js를 선호합니다. 내가 사용한 것은 is이며 underscore.flatten(), 배열 배열을 취한다는 점에서 결합보다 낫습니다.
weaver

8
@weaver _.flatten은 병합되지만 '복제'하지는 않습니다.
GijsjanB


288

먼저 두 배열을 연결 한 다음 고유 항목 만 필터링하십시오.

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

편집하다

제안 된대로보다 현명한 솔루션은 다음 b과 연결하기 전에 고유 항목을 필터링하는 것 입니다 a.

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]


5
여기서 원래 솔루션은 각 소스 배열 내에서 듀피를 제거 할 수 있다는 이점이 있습니다. 나는 그것이 당신이 사용할 문맥에 달려 있다고 생각합니다.
theGecko

IE6-support와는 다르게 병합 할 수 있습니다. c = Array.from (new Set (c));
Tobi G.

실제로 aadd로 변경 b하려면 반복하고 푸시를 사용하는 것이 더 낫습니까? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
awe

1
IE6에 관심이있는 사람들을 위해 현재 브라우저 사용 caniuse.com/usage-table 을 상기시킵니다 .
pmrotule

10
@Andrew : 더 나은 : 1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
7vujy0f0hy

203

이것은 스프레드 연산자 와 배열 제네릭을 사용하는 ECMAScript 6 솔루션 입니다.

현재는 Firefox 및 Internet Explorer Technical Preview에서만 작동합니다.

그러나 Babel 을 사용 하면 지금 가질 수 있습니다.

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));


14
허용 된 답변에 추가해야합니다. 이 솔루션은 현재 가능한 것보다 훨씬 효율적이고 우아하지만 우리가 불가피하게 할 수있는 일입니다 (그리고이 분야를 계속 유지해야합니다).
EmmaGamma

이것은 OP의 질문과 똑같지 않지만 (이것은 다른 것보다 플랫 맵 인 것 같습니다) 훌륭하기 때문에 찬성합니다.
jedd.ahyoung

4
2009 년 이후로이 질문에 대한 답을 받아 들여야한다고 말하기는 어렵습니다. 그러나 그렇습니다. 이것은 더 "성능 적"일뿐만 아니라 "우아한"입니다
Cezar Augusto

11
Array.from대신에 확산 연산자 사용할 수 있습니다 : Array.from(new Set([].concat(...arr)))
헨리 블리스에게

1
이것은 매우 우아합니다. 불행히도 Typescript는 아직 이것을 지원하지 않습니다. stackoverflow.com/questions/33464504/…
벤 잉어

190

ES6

array1.push(...array2) // => don't remove duplication 

또는

[...array1,...array2] //   =>  don't remove duplication 

또는

[...new Set([...array1 ,...array2])]; //   => remove duplication

1
첫 번째 / 두 번째 예는 전혀 union+ 첫 Array번째 예는 큰 s에 대한 스택을 날려 버립니다. + 세 번째 예는 엄청나게 느리고 많은 메모리를 소비합니다. 두 개의 중간 Array을 빌드해야합니다 + 세 번째 예는 union알려진 것으로 만 사용할 수 있기 때문입니다 Array컴파일시의 수

어떻게 하시겠습니까?
David Noreña

14
Set가는 길입니다
philk

3
set에 대해서는 동일한 객체 참조가 아닌 한 동일한 키 값 쌍을 갖는 두 객체를 중복 제거 할 수 없습니다.
Jun711

2
객체 참조 만 병합하고 객체 자체가 동일한 지 신경 쓰지 않으므로 객체 배열에서는 작동하지 않습니다.
Wilson Biggs

87

사용 설정 (2015 인 ECMAScript)를, 그 한 간단하게 될 것입니다 :

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
console.log(Array.from(new Set(array1.concat(array2))));


7
ES6 사용에 대한 "허용 된 답변"이라고 생각합니다.
mwieczorek

9
@mwieczorek 방법 :const array3 = [...new Set(array1.concat(array2))]
로비 코넬리 센

5
객체 배열을 사용하는 경우 작동하지 않습니다.
carkod

1
stackoverflow.com/a/54134237/3131433 : 복제하지 않고 다른 개체를 병합
Rakibul 하크을

38

루프에 약간의 차이가 있습니다. 최신 버전의 Chrome에서 일부 최적화 기능을 사용하면 두 배열의 통합을 해결하는 가장 빠른 방법입니다 (Chrome 38.0.2111).

http://jsperf.com/merge-two-arrays-keeping-only-unique-values

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

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

while 루프 : ~ 589k ops / s
필터 : ~ 445k ops / s
lodash :
루프 의 경우 308k ops / s : 225k ops / s

의견에 따르면 내 설정 변수 중 하나가 쓰기 위해 빈 배열을 초기화 할 필요가 없기 때문에 루프가 나머지 루프보다 우선합니다. 나는 이에 동의하므로 테스트를 경기장까지 다시 작성했으며 더 빠른 옵션을 포함 시켰습니다.

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/52

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

이 대체 솔루션에서는 하나의 답변의 연관 배열 솔루션을 결합 .indexOf()하여 루프 에서 호출 을 제거하여 두 번째 루프로 많은 속도를 늦췄으며 다른 사용자가 제안한 다른 최적화도 포함했습니다. .

모든 값 (i-1)에서 이중 루프를 사용하는 가장 좋은 대답은 여전히 ​​상당히 느립니다. lodash는 여전히 강력하고 있으며 프로젝트에 라이브러리를 추가하지 않는 사람에게는 여전히 좋습니다. 원하지 않는 사람들을 위해, 내 while 루프는 여전히 좋은 대답이며 필터 답변은 여기에 매우 강력하게 표시 되어이 글을 쓰는 시점에서 최신 Canary Chrome (44.0.2360)으로 내 테스트를 모두 능가합니다.

체크 아웃 마이크의 대답댄 스토커의 답변을 당신이 속도 노치를 그것을 단계로합니다. 그것들은 거의 모든 가능한 답변을 거친 후 모든 결과 중 가장 빠릅니다.


방법론에 결함이 있습니다. array3 작성을 설정 단계에 두는 반면, 비용은 귀하의 솔루션 기반 점수의 일부일뿐입니다. 이 1 행을 이동 하면 솔루션이 for 루프 기반의 속도로 떨어집니다. 배열을 재사용 할 수는 있지만 다른 알고리즘도 필요한 모든 빌딩 블록을 선언하고 초기화하지 않아도 도움이 될 수 있습니다.
doldt

귀하의 전제 @doldt에 동의하지만 결과에 동의하지 않습니다. 항목을 제거한 후 배열의 길이를 다시 확인해야하므로 실행 시간이 느려지므로 루프 기반의 항목 제거에 대한 근본적인 설계 결함이 있습니다. 거꾸로 작동하는 while 루프에는 이러한 효과가 없습니다. 다음은 원래 답변을 너무 많이 변경하지 않고 가능한 많은 설정 변수를 제거하는 예입니다. jsperf.com/merge-two-arrays-keeping-only-unique-values/19
slickplaid

@slickplaid 연결된 테스트가 비어 있고 jsperf의 다음 개정판이 while 루프에 중단됩니다.
doldt

@doldt 나는 내 대답에 대한 귀하의 우려를 해결하고 그것에 대한 업데이트 된 적절한 테스트를 추가했습니다. 해당 결과에 동의하는지 여부를 알려주십시오. 또한 연관 배열을 사용하여 더 나은 결과를 추가했습니다.
slickplaid

1
@slickplaid 확장 된 성능 페이지를 설정해 주셔서 감사합니다. 내가 빠진 것이 아니라면 "whileLoopAlt2"기능이 작동하지 않습니까? 첫 번째 배열과 두 번째 배열 (역순)을 포함하는 새 배열을 만듭니다. 혼란을 피하기 위해 깨진 기능을 제거하는 또 다른 수정본을 만들었습니다. 또한 추가 예를 추가했습니다. jsperf.com/merge-two-arrays-keeping-only-unique-values/22
Stephen S

37

ECMAScript 6을 사용하여 간단하게 수행 할 수 있습니다.

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • 배열을 연결 하려면 스프레드 연산자 를 사용하십시오 .
  • 고유 한 요소 세트 를 작성 하려면 세트 를 사용 하십시오 .
  • 다시 스프레드 연산자를 사용하여 Set을 배열로 변환하십시오.

2
오류가 발생합니다. 'Set <string>'유형이 배열 유형이 아닙니다.
gattsbr

3
어떤 이유로 스프레드 연산자를 사용하지 않으려는 경우 다음도 있습니다 Array.from(new Set(array1.concat(array2)))..
kba

@gattsbr에서 타이프 라이터와 함께 tsconfig.json, 당신은 추가 할 수 있습니다 "downlevelIteration": truecompilerOptions.
VincentPerrin.com

19
Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

훨씬 나은 배열 병합 기능.


4
var test = ['a', 'b', 'c']; console.log(test); 인쇄 ["a", "b", "c", merge: function]
Doubidou

탁월한 솔루션. @slickplaid ( jsperf.com/merge-two-arrays-keeping-only-unique-values/3 )에 의해 게시 된 jsperf 테스트를 업데이트했으며 이것이 가장 빠른 것 같습니다.
Cobra

@Cobra Chrome 40.0.2214 (최신 2/18/15 기준)에서 실행시 사소한 소리가 날 위험이 있습니다.이 답변은 내 것보다 53 % 느립니다. OTOH IE11은 내 대답에 전혀 최적화되지 않은 것 같습니다. :) 크롬 모바일은 여전히 ​​흔들리고 있습니다. 솔직히, 대부분의 사람들이 사용해야 할 lodash / _를 사용하고 있다면 진정한 대답은 이미이 목록에서 상당히 높습니다. :)
slickplaid

@slickplaid True이며 lodash / _에 비해 훨씬 빠릅니다. 아마도 구현을 한 시점에서 다른 것과 비슷한 것으로 바꿀 것입니다. : D
코브라

1
indexOf () 메소드의 비용이 얼마인지 확실하지 않지만 아마도 가장 빠른 ES5 호환 메소드 일 것입니다. 또한 가변 길이의 인수가 필요하지 않다는 점도 가치가 없습니다. 이 방법은 체인 가능합니다. @slickplaid 라이브러리를로드한다고해서 "자바 스크립트에서하는 방법"질문에 대한 답은 결코 아닙니다. 분명히 많은 라이브러리에는이 7 줄 작업을 수행하는 기능이 있습니다.
dehart

19

그냥 내 두 센트에 던져.

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

이것은 내가 많이 사용하는 방법이며, 객체를 해시 조회 테이블로 사용하여 중복 검사를 수행합니다. 해시가 O (1)이라고 가정하면 O (n)에서 실행됩니다. 여기서 n은 a.length + b.length입니다. 브라우저가 해시를 어떻게 수행하는지 잘 모르겠지만 수천 개의 데이터 포인트에서 잘 작동합니다.


아주 잘 했어요 연관 배열을 활용하고 indexOf 및 기타 연산의 루핑을 유지함으로써이 페이지의 다른 결과 중 상당 부분을 능가합니다. jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

"해시"는 String()자바 스크립트 의 함수입니다. 기본 값 (유형 사이의 충돌에도 불구하고)에 작동 할 수 있지만 객체 배열에는 적합하지 않습니다.
Bergi

비슷한 솔루션을 사용합니다. 해시 코드 함수를 전달하거나 문자열을 전달하여 해시 키로 사용할 객체의 속성을 식별 할 수 있습니다.
Robert Baker

19

중첩 루프 (O (n ^ 2))와 .indexOf()(+ O (n))을 피하십시오.

function merge(a, b) {
    var hash = {}, i;
    for (i=0; i<a.length; i++) {
        hash[a[i]]=true;
    } 
    for (i=0; i<b.length; i++) {
        hash[b[i]]=true;
    } 
    return Object.keys(hash);
}

2
특히 현을 연주하는 경우에는 정말 놀랍습니다. 숫자를 그대로 유지하려면 추가 단계가 필요합니다. 이 기능은 작업이 끝난 후에 모든 것이 문자열이라는 것을 신경 쓰지 않으면 모든 다른 옵션을 크게 능가합니다. 좋은 작업. 여기에 성능 결과 : jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

18

이 답변을 최대한 활용 하고 훌륭한 기능으로 전환했습니다.

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}

2
나는 이것이 받아 들인 대답보다 훨씬 깨끗하다고 ​​생각합니다. 또한 ECMAScript 5.1 +에서 필터가 지원되는 것 같습니다.
Tom Fobear

이 허용되어 있어야합니다
구타

이것은 훨씬 간결합니다.
Mox

15

왜 물건을 사용하지 않습니까? 세트를 모델링하려는 것 같습니다. 그러나 이것은 순서를 유지하지 않습니다.

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

당신은 의미하지 if (!set1.hasOwnProperty(key))않습니까?
Gumbo

2
내가 왜 그러 겠어? 해당 조건의 목적은 객체의 프로토 타입에있을 수있는 속성을 무시하는 것입니다.
Nick Retallack 19

12

최고의 솔루션 ...

당신은 타격하여 브라우저 콘솔에서 직접 확인할 수 있습니다 ...

중복하지 않고

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

중복

["prince", "asish", 5].concat(["ravi", 4])

중복없이 원하는 경우에 당신은 여기에서 더 나은 솔루션을 시도 할 수 있습니다 - 코드를 외치고 .

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

Chrome 브라우저 콘솔에서 사용해보기

 f12 > console

산출:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

출력 배열에서 중복을 제거하지 않습니다.
Shahar

9

내 반 페니 :

Array.prototype.concat_n_dedupe = function(other_array) {
  return this
    .concat(other_array) // add second
    .reduce(function(uniques, item) { // dedupe all
      if (uniques.indexOf(item) == -1) {
        uniques.push(item);
      }
      return uniques;
    }, []);
};

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

var result = array1.concat_n_dedupe(array2);

console.log(result);

ES6의 새로운 기능은 사용하지 않습니다.
Bergi

@ Bergi : 네, 맞습니다. 주목 해 주셔서 감사합니다. 어떻게 든이 스크립트를 사용하고 있었으며 아마도 ES6 기능이있는 버전이 있었지만 이제는 수세기 동안 indexOf가 포함되어 있습니다. 내 실수, 미안
Hero Qu

8

Underscore.js의 => uniq을 사용하여 간단히 달성 할 수 있습니다 .

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

console.log(array3)

[ "Vijendra", "Singh", "Shakya"] 가 인쇄됩니다 .


7

ES6의 경우 한 줄만 :

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]

7

나는이 질문이 객체 배열에 관한 것이 아니라 검색자가 여기에 있다는 것을 알고 있습니다.

따라서 미래의 독자들을 위해 적절한 ES6 방식을 병합하고 중복 제거하는 것이 좋습니다.

객체 배열 :

var arr1 = [ {a: 1}, {a: 2}, {a: 3} ];
var arr2 = [ {a: 1}, {a: 2}, {a: 4} ];

var arr3 = arr1.concat(arr2.filter( ({a}) => !arr1.find(f => f.a == a) ));

// [ {a: 1}, {a: 2}, {a: 3}, {a: 4} ]

6
//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

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

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

indexOf다른 브라우저에 대한 메소드 구현은 MDC 에서 가져옵니다.


1
나는 w3schools에서 그것을 찾을 수 없었기 때문에 그것을 썼다. w3schools.com/jsref/jsref_obj_array.asp 합니까 그것은 걸릴 fromBTW 매개 변수를?
Amarghosh

@Gumbo와 @meder에게 감사드립니다-내 북마크를 변경하겠습니다. 나는 js에서 아직 심각한 일을하고 있지 않으며 w3schools를 캐주얼 참조로 사용합니다 (필요한 전부입니다). 그래서 내가 그것을 깨닫지 못했을 수도 있습니다.
Amarghosh

MDC에 따르면 indexOf에는 자바 스크립트 1.6이 필요합니다. 공통 브라우저 (> = FF2,> IE6 등)가이를 지원한다고 가정해도 안전합니까?
Amarghosh 09 년

4
IE6는 Array.prototype.indexOf를 지원하지 않습니다. 모질라가 제공 한 지원 메소드를 붙여 넣기 만하면 IE가 오류를 발생시키지 않습니다.
meder omuraliev

를 사용하여 업데이트했습니다 indexOf. 주석 처리 된 부분을 제거하여 코드를 정리했습니다. @meder-다시 감사합니다.
Amarghosh

6

새로운 솔루션 ( Array.prototype.indexOf및 사용 Array.prototype.concat) :

Array.prototype.uniqueMerge = function( a ) {
    for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
        if ( this.indexOf( a[i] ) === -1 ) {
            nonDuplicates.push( a[i] );
        }
    }
    return this.concat( nonDuplicates )
};

용법:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

인터넷 익스플로러의 경우 Array.prototype.indexOf :

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

@Mender : 주문이 중요하지 않으면 어떻게해야합니까
Vijjendra

1
Array.prototype에 대해 정의 된 표준 ECMAScript 방법은 아니지만 IE 및 지원하지 않는 다른 브라우저에 대해 쉽게 정의 할 수 있다는 것을 알고 있습니다.
meder omuraliev

이 알고리즘은 O (n ^ 2)입니다.
Gumbo

답은 어떤 알고리즘입니까?
meder omuraliev

@meder : 내 알고리즘은 통합 알고리즘입니다. 조합 자체는 O (n + m)에서 수행되지만 정렬에는 최대 O (n · log n + m · log m)가 걸립니다. 따라서 전체 알고리즘은 O (n · log n + m · log m)입니다.
Gumbo

6

Set을 사용하여 수행 할 수 있습니다.

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

var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);

//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
  temp text 
</div>


6

두 어레이를 병합하기위한 솔루션이 너무 많습니다. lodash 또는 underscore.js와 같은 타사 라이브러리 사용을 제외하고 두 가지 주요 범주로 나눌 수 있습니다.

a) 두 배열을 결합하고 중복 된 항목을 제거합니다.

b) 항목을 결합하기 전에 필터링하십시오.

두 배열을 결합하고 중복 된 항목 제거

결합

// mutable operation(array1 is the combined array)
array1.push(...array2);
array1.unshift(...array2);

// immutable operation
const combined = array1.concat(array2);
const combined = [...array1, ...array2];    // ES6

통일

배열을 통합하는 방법에는 여러 가지가 있습니다. 개인적으로 아래 두 가지 방법을 제안합니다.

// a little bit tricky
const merged = combined.filter((item, index) => combined.indexOf(item) === index);
const merged = [...new Set(combined)];

항목을 결합하기 전에 필터링

여러 가지 방법이 있지만 간단하기 때문에 아래 코드를 개인적으로 제안합니다.

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));

5
Array.prototype.add = function(b){
    var a = this.concat();                // clone current object
    if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
    if(!a.length) return b.concat();      // if original is empty, return b

    // go through all the elements of b
    for(var i = 0; i < b.length; i++){
        // if b's value is not in a, then add it
        if(a.indexOf(b[i]) == -1) a.push(b[i]);
    }
    return a;
}

// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]

5
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

이것에 대한 좋은 점은 성능이며 일반적으로 배열로 작업 할 때 필터, 맵 등과 같은 메소드를 연결하여 해당 줄을 추가 할 수 있으며 나중에 참조 할 필요없이 array2와 array2를 연결하고 중복 제거합니다 하나 (당신이 가지고 있지 않은 연결 방법 인 경우), 예 :

someSource()
.reduce(...)
.filter(...)
.map(...) 
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc

(나는 Array.prototype을 오염시키는 것을 좋아하지 않으며 체인을 존중하는 유일한 방법이 될 것입니다-새로운 함수를 정의하면 깨질 것입니다. 그래서 이와 같은 것이 그것을 달성하는 유일한 방법이라고 생각합니다)


4

당신은 이것을 시도 할 수 있습니다 :

const union = (a, b) => Array.from(new Set([...a, ...b]));

console.log(union(["neymar","messi"], ["ronaldo","neymar"]));


3

ES2015를 통한 기능적 접근

기능적 접근에 union따라 두 가지 중 하나 Array의 a 는 concat및 의 구성입니다 filter. 최적의 성능을 제공하기 Set위해 속성 조회에 최적화 된 기본 데이터 유형을 사용합니다.

어쨌든, union기능 과 관련하여 중요한 질문은 중복을 처리하는 방법입니다. 다음과 같은 순열이 가능합니다.

Array A      + Array B

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

처음 두 순열은 단일 함수로 처리하기 쉽습니다. 그러나 마지막 두 개는 Set조회에 의존하는 한 처리 할 수 ​​없으므로 더 복잡 합니다. 일반 오래된 Object속성 조회로 전환 하면 심각한 성능 저하가 수반되므로 다음 구현에서는 세 번째 및 네 번째 순열을 무시합니다. union이를 지원하기 위해 별도의 버전을 구축 해야합니다.


// small, reusable auxiliary functions

const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// de-duplication

const dedupe = comp(afrom) (createSet);


// the actual union function

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];


// here we go

console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );

여기에서 unionn(naomik의 의견에서 영감을 얻은) 많은 수의 배열을 허용 하는 함수 를 구현하는 것이 쉽지 않습니다.

// small, reusable auxiliary functions

const uncurry = f => (a, b) => f(a) (b);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// union and unionn

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}

const unionn = (head, ...tail) => foldl(union) (head) (tail);


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];


// here we go

console.log( unionn(xs, ys, zs) );

그것은 unionn단지 foldl(일명 Array.prototype.reduce)이며, union감속기로 사용됩니다. 참고 : 구현시 추가 누산기를 사용하지 않으므로 인수없이 적용하면 오류가 발생합니다.


1
몇 피드백 : 나는 것을 발견 flip하고 notf사용되지 않는다. 또한 unionBy술어는 구현 세부 사항을 누설합니다 (암시 적 Set유형의 지식이 필요함 ). 다음과 같이 할 수 있다면 좋을 것입니다 : union = unionBy (apply)unionci = unionBy (p => x => p(x.toLowerCase())). 그렇게하면 사용자는 그룹화 값에 관계없이 모든 것을 보냅니다. p^ _ ^
감사합니다.

zs변수 선언도 var/ let키워드 가 부족 합니다
감사합니다.

1
다음은 명확하게 설명하는 코드 스 니펫입니다. [gist : unionBy.js ]
감사합니다.

@naomik 내 솔루션을 잠시 동안 다시 생각한 후에는 술어를 전달하는 올바른 방법인지 더 이상 확실하지 않습니다. 두 번째 배열의 각 요소를 변형하면됩니다. 이 접근법이 단순한 장난감 문제 이상을 해결하는지 궁금합니다.

3

그것을 위해 ... 여기에 단일 라인 솔루션이 있습니다 :

const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
// ['A', 'B', 'C']

특히 읽을 수는 없지만 누군가에게 도움이 될 수 있습니다.

  1. 초기 누산기 값을 빈 배열로 설정하여 축소 기능을 적용합니다.
  2. reduce 함수는 concat을 사용하여 각 하위 배열을 누산기 배열에 추가합니다.
  3. 이것의 결과는 생성자 매개 변수로 전달되어 새로운을 작성합니다 Set.
  4. 스프레드 연산자는를 Set배열 로 변환하는 데 사용됩니다 .
  5. sort()함수는 새 배열에 적용됩니다.

2
또한 대신 reduce()사용할 수 있습니다Array.from(set)
Eran Goldin

3

단일 중복 제거 또는 여러 어레이 입력 병합 및 중복 제거. 아래 예.

ES6 사용-설정, 구성 해제

여러 배열 인수를 취하는이 간단한 함수를 작성했습니다. 위의 솔루션과 거의 동일하게 더 실용적인 사용 사례가 있습니다. 이 함수는 중복 값을 하나의 배열에만 연결하지 않으므로 나중에 나중에 삭제할 수 있습니다.

단축 기능 정의 (단 9 줄)

/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
   let set = new Set(); // init Set object (available as of ES6)
   for(let arr of args){ // for of loops through values
      arr.map((value) => { // map adds each value to Set object
         set.add(value); // set.add method adds only unique values
      });
   }
   return [...set]; // destructuring set object back to array object
   // alternativly we culd use:  return Array.from(set);
}

사용 예 코드 펜 :

// SCENARIO 
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = ['a','b','c','d'];
let e = ['b','c','d','e'];

// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);

// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]

arr.map여기에 사용 합니까? foreach결과가 무시되므로
Antony

내가 사용 Array.from (set.values을 ()) 반환; vscode는 리턴
makkasi

3
var arr1 = [1, 3, 5, 6];
var arr2 = [3, 6, 10, 11, 12];
arr1.concat(arr2.filter(ele => !arr1.includes(ele)));
console.log(arr1);

output :- [1, 3, 5, 6, 10, 11, 12]

3

var array1 = ["one","two"];
var array2 = ["two", "three"];
var collectionOfTwoArrays = [...array1, ...array2];    
var uniqueList = array => [...new Set(array)];
console.log('Collection :');
console.log(collectionOfTwoArrays);    
console.log('Collection without duplicates :');
console.log(uniqueList(collectionOfTwoArrays));

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.