JavaScript에서 두 배열의 차이점을 얻는 방법은 무엇입니까?


751

JavaScript에서 두 배열의 차이를 반환하는 방법이 있습니까?

예를 들면 다음과 같습니다.

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

// need ["c", "d"]

9
대칭 또는 비대칭?
궤도에서 가벼움 경주

새로운 ES6 기능을 사용하면 간단한 단일 라이너로 수행 할 수 있습니다 (모든 주요 브라우저에서 사용할 수 있으려면 시간이 오래 걸립니다). 어쨌든 내 대답을
Salvador Dali

1
솔루션의 중요한 측면은 성능입니다. 이 유형의 연산의 점근 적 시간 복잡성-다른 언어로- O(a1.length x log(a2.length))이 성능은 JavaScript에서 가능합니까?
Raul

답변:


218

일반 배열을 비교한다고 가정합니다. 그렇지 않은 경우 for 루프를 for .. in 루프 로 변경해야합니다 .

function arr_diff (a1, a2) {

    var a = [], diff = [];

    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (var k in a) {
        diff.push(k);
    }

    return diff;
}

console.log(arr_diff(['a', 'b'], ['a', 'b', 'c', 'd']));
console.log(arr_diff("abcd", "abcde"));
console.log(arr_diff("zxc", "zxc"));

이전 버전과의 호환성에 관심이없는 경우 더 나은 솔루션은 필터를 사용하는 것입니다. 그러나 여전히이 솔루션은 작동합니다.


46
이것은 작동하지만 Array의 필터 메소드를 사용하여 한 줄의 코드로 수행 할 수있는 작업을 수행하기 위해 세 개의 루프를 수행합니다.
Joshaven Potter

9
명확히하기 위해 여기에 게시 된 다른 답변과 달리 a1a2대칭 차이 를 구현합니다 .
200_success

25
이것이 최선의 대답은 아니지만 불공정 한 다운 보트를 보충 할 수 있도록 자선 공감대를 제공하고 있습니다. 잘못된 답변 만 다운 보트해야하며, 범위 내에서 cruft-browsers를 사용하여 프로젝트를 진행하는 경우 (거친 시간 발생)이 답변이 도움이 될 수도 있습니다.
Michael Scheper

3
나는 때 무슨 일이 일어날 지 알 수 있음 var a1 = ['a', 'b'];var a2 = ['a', 'b', 'c', 'd', 'b'];, 그것은 잘못된 답을 반환합니다 즉, ['c', 'd', 'b']대신 ['c', 'd'].
skbly7

4
가장 빠른 방법은 가장 순진한 솔루션입니다. 이 스레드에서 대칭 diff에 대해 제안 된 모든 솔루션을 테스트했으며 우승자는 다음과 같습니다.function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
Nomaed

1227

ES7을 사용하는 더 좋은 방법이 있습니다.


교차로

 let intersection = arr1.filter(x => arr2.includes(x));

교차점 차이 벤 다이어그램

들어 [1,2,3] [2,3]는 얻을 것입니다 [2,3]. 반면에 for [1,2,3] [2,3,5]는 같은 것을 반환합니다.


let difference = arr1.filter(x => !arr2.includes(x));

오른쪽 차이 벤 다이어그램

들어 [1,2,3] [2,3]는 얻을 것입니다 [1]. 반면에 for [1,2,3] [2,3,5]는 같은 것을 반환합니다.


A에 대한 대칭 적 차이 , 당신은 할 수 있습니다 :

let difference = arr1
                 .filter(x => !arr2.includes(x))
                 .concat(arr2.filter(x => !arr1.includes(x)));

대칭 차이 벤 다이어그램

이 방법으로 arr2에 있지 않은 arr1의 모든 요소를 ​​포함하는 배열을 얻습니다.

@Joshaven Potter가 그의 답변에서 지적했듯이 이것을 Array.prototype에 추가하여 다음과 같이 사용할 수 있습니다.

Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])

3
< 0대신 확인하는 것이 좋습니다== -1
Vic

1
속성 룩업은 s의 고유 한 작업이기 때문에 Array차이를 계산 하는 것은 이른바 set operation, / Set보다 빠르다 . 간단히 말해, 솔루션은 매우 비효율적이며 다소 느립니다. indexOfincludes

@ftor이지만 Set값은 고유해야합니다.
CervEd

1
@LuisSieira 나는 [1,2,3] [2,3,5]숫자가 독특하다는 것을 감안할 때 효과가있을 것이라고 말하지만 당신이 말하고 [1,1,2,3] [1,2,3,5]기대 [1]하면 사용할 수 없습니다 Set. 귀하의 솔루션도 작동하지 않을 것입니다 :-/ 더 간결하게 수행 할 수있는 만족스러운 방법을 알 수 없기 때문에이 기능 을 만들었습니다 . 그렇게하는 방법에 대한 아이디어가 있다면 알고 싶습니다!
CervEd

3
아닌가 Array.includes()대신 ES6의 ES7 기능은? (1) (2) — 계속하려면 ES6을 사용하여 Array.some()예를 들어 let intersection = aArray.filter(a => bArray.some(b => a === b))no?
Jari Keinänen

910
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

[1,2,3,4,5,6].diff( [3,4,5] );  
// => [1, 2, 6]

["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
// => ["test5", "test6"]

참고 indexOf 및 필터는 ie9 이전에는 사용할 수 없습니다.


50
filter와 indexOf를 지원하지 않는 유일한 브라우저는 IE8입니다. IE9는 둘 다 지원합니다. 따라서 잘못이 아닙니다.
Bryan Larsen

14
ie7과 ie8은 여전히 ​​(아쉽게도) 매우 관련이 있지만 MDN 사이트에서 두 기능에 대한 polyfill 코드를 찾을 수 있습니다. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… developer.mozilla.org/en/JavaScript/ Reference / Global_Objects /… IE 조건부 & BOOM을 통해 "호환성"에 나열된 코드를로드하십시오. IE7 / 8이 지원됩니다.
1nfiniti

44
이 솔루션의 런타임은 O (n ^ 2)이며 선형 솔루션이 훨씬 더 효율적입니다.
jholloman

75
다음과 같이 함수를 사용하면 대신 [1,2,3].diff([3,4,5])반환 되어 원래 질문의 문제를 해결하지 못합니다. [1,2][1,2,4,5]
Bugster

12
@AlinPurcaru 구식 브라우저에서 지원되지 않습니다! = 잘못되었습니다. Netscape 2.0을 고려할 때 여기에있는 대부분의 JS 코드는이 정의에 의해 "잘못된"것입니다. 어리석은 말입니다.
NullUserException

304

이것은 jQuery를 사용하여 원하는 결과를 정확하게 얻는 가장 쉬운 방법입니다.

var diff = $(old_array).not(new_array).get();

diff지금에 무슨 포함 old_array그게 아닙니다new_array


4
@Batman 예, 그러나 동일한 객체에 대한 참조 인 경우에만 해당 {a: 1} != {a: 1}( 증거 )
Matmarbon

사용자 정의 객체의 데이터를 보유하는 배열과 함께 사용할 수 있습니까? 실제로 같은 방식으로 시도했지만 작동하지 않았습니다. 모든 아이디어는 매우 감사 할 것입니다.
LetMeCodeYou

8
이게 속임수입니까? 이 문서 는이 메소드를 일반적인 배열 도우미가 아닌 DOM 요소 메소드의 일부로 간주합니다 . 따라서 지금은이 방법으로 작동 할 수 있지만이 방법으로 사용하지 않으므로 향후 버전에서는 작동하지 않을 수 있습니다. 비록 공식적으로 일반적인 배열 도우미가된다면 기쁠 것입니다.
robsch

1
@robsch .not배열과 함께 사용하면 jQuery는 .grep()배열을 필터링하기 위해 내장 유틸리티 를 사용합니다. 이 변화를 볼 수 없습니다.
superphonic

1
@vsync 소리 당신은 대칭 차이 후처럼
superphonic

158

Underscore (또는 드롭 인 대체 Lo-Dash ) 의 차이점 방법으로 도 다음을 수행 할 수 있습니다.

(R)eturns the values from array that are not present in the other arrays

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

Underscore 함수와 마찬가지로보다 객체 지향 스타일로 사용할 수도 있습니다.

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);

4
특히 lodash와 underscore가 최상의 구현을 위해 싸우고 있기 때문에 성능면에서 좋은 솔루션이라고 생각합니다. 또한 IE6와 호환됩니다.
mahemoff

4
이 구현은 객체 배열에는 작동하지 않습니다. 자세한 내용은 stackoverflow.com/q/8672383/14731 을 참조하십시오.
길리

1
답변 중 하나가 언급했듯이 동일한 객체 인 경우 작동하지만 두 객체의 속성이 동일한 경우 작동하지 않습니다. 평등의 개념이 다양하므로 괜찮습니다 (예 : 일부 앱에서 "id"속성 일 수도 있음). 그러나 비교 테스트를 통과하여 intersect () 할 수 있다면 좋을 것입니다.
mahemoff 2019 년

후손을 위해 : Lodash는 이제 비교를 위해 콜백을받는 _.differenceBy ()를 갖습니다. 객체를 비교하는 경우 필요에 따라 객체를 비교하는 함수를 사용할 수 있습니다.
SomeCallMeTim

2
인수 순서가 반대로 바뀌면 작동하지 않습니다. 예. _. 차이 ([5, 2, 10], [1, 2, 3, 4, 5]); diff를 얻을 수 없습니다
Russj

79

일반 자바 스크립트

"차이"에 대한 두 가지 가능한 해석이 있습니다. 원하는 것을 고를 수 있도록하겠습니다. 당신이 가지고 있다고 :

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. 을 얻으려면 ['a']이 함수를 사용하십시오.

    function difference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      return result;
    }
  2. ['a', 'c']( 또는 소위 대칭 차이 라는 둘 중 하나 a1 또는에 포함 된 모든 요소) 를 얻으려면 이 함수를 사용하십시오.a2

    function symmetricDifference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.push(a1[i]);
        }
      }
      for (i = 0; i < a2.length; i++) {
        if (a1.indexOf(a2[i]) === -1) {
          result.push(a2[i]);
        }
      }
      return result;
    }

Lodash / 밑줄

lodash를 사용하는 _.difference(a1, a2)경우 (위의 경우 1) 또는 _.xor(a1, a2)(경우 2)를 사용할 수 있습니다 .

Underscore.js를 사용하는 경우 _.difference(a1, a2) 경우 사례 1 기능을 .

매우 큰 어레이를위한 ES6 세트

위의 코드는 모든 브라우저에서 작동합니다. 그러나 약 10,000 개가 넘는 항목의 대형 배열의 경우 O (n²) 복잡도를 갖기 때문에 상당히 느려집니다. 많은 최신 브라우저에서 ES6 Set객체를 활용 하여 작업 속도를 높일 수 있습니다. Lodash는 사용 Set가능한 경우 자동으로 사용 합니다. lodash를 사용하지 않는 경우 Axel Rauschmayer의 블로그 게시물 에서 영감을 얻은 다음 구현을 사용하십시오 .

function difference(a1, a2) {
  var a2Set = new Set(a2);
  return a1.filter(function(x) { return !a2Set.has(x); });
}

function symmetricDifference(a1, a2) {
  return difference(a1, a2).concat(difference(a2, a1));
}

노트

-0, +0, NaN 또는 희소 배열 을 신경 쓰면 모든 예제의 동작이 놀랍거나 분명하지 않을 수 있습니다. (대부분의 경우, 이것은 중요하지 않습니다.)


감사. 당신은 내 하루를 구했다. 300K 어레이를 비교해야했으며 "Set"솔루션이 완벽하게 작동했습니다. 이것이 정답입니다.
justadev

52

대칭적인 차이 를 얻으려면 두 가지 방법으로 (또는 여러 배열의 경우 모든 방법으로) 배열을 비교해야합니다.

여기에 이미지 설명을 입력하십시오


ES7 (ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}

ES6 (ECMAScript 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}

ES5 (ECMAScript 5.1)

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

예:

// diff between two arrays:
const a = ['a', 'd', 'e'];
const b = ['a', 'b', 'c', 'd'];
arrayDiff(a, b); // (3) ["e", "b", "c"]

// diff between multiple arrays
const a = ['b', 'c', 'd', 'e', 'g'];
const b = ['a', 'b'];
const c = ['a', 'e', 'f'];
arrayDiff(a, b, c); // (4) ["c", "d", "g", "f"]

객체 배열의 차이점

function arrayDiffByKey(key, ...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter( x =>
            !unique.some(y => x[key] === y[key])
        );
    }));
}

예:

const a = [{k:1}, {k:2}, {k:3}];
const b = [{k:1}, {k:4}, {k:5}, {k:6}];
const c = [{k:3}, {k:5}, {k:7}];
arrayDiffByKey('k', a, b, c); // (4) [{k:2}, {k:4}, {k:6}, {k:7}]

50

ES6의 깔끔한 접근 방식은 다음과 같습니다.

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

a2.filter(d => !a1.includes(d)) // gives ["c", "d"]

교차로

a2.filter(d => a1.includes(d)) // gives ["a", "b"]

이산 연합 (대칭 차이)

[ ...a2.filter(d => !a1.includes(d)),
  ...a1.filter(d => !a2.includes(d)) ]

한 방향으로 만 작동합니다. 이제 상상 a1 = ['a', 'b', 'e']: 전자가 추출되지 않습니다.
imrok

그렇습니다. 설정 이론의 차이가 작동하는 방식입니다. (a2-a1) 찾고있는 것은 (a2-a1) + (a1-a2)
ifelse.codes

1
@ imrok 나는 이것이 당신이 찾고있는 것이라고 생각합니다 ...... a2.filter (d =>! a1.includes (d)), ... (a1.filter (d =>! a2.includes (d)) )]
ifelse.codes

2
아름다운 솔루션, 감사합니다!
Thiago Alves

40

이 경우 Set 을 사용할 수 있습니다 . 이런 종류의 작업 (유니온, 교차, 차이)에 최적화되어 있습니다.

중복이 허용되지 않는 경우 귀하의 사례에 적용되는지 확인하십시오.

var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
var b = new JS.Set([2,4,6,8]);

a.difference(b)
// -> Set{1,3,5,7,9}

4
멋진 도서관 같아요! Set다른 모든 것을 얻지 않고 함수 만 다운로드 할 수 없다는 것은 부끄러운 일입니다 ...
Blixt

@Blixt 모든 파일을 다운로드 할 수 있다고 믿고 set.js 파일 만 포함하십시오
Samuel Carrijo

Google 클로저에서도 세트가 구현됩니다. closure-library.googlecode.com/svn/docs/…
벤 플린


32
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

두 배열을 병합하면 고유 값이 한 번만 나타나므로 indexOf ()는 lastIndexOf ()와 같습니다.


3
나는 이것이 가장 깨끗하고 간단한 방법이며 프로토 타입을 만질 필요가 없다는 것에 동의합니다. "만 6 세까지 설명 할 수 없다면 스스로 이해하지 못하는 것입니다." ― Albert Einstein
lacostenycoder

18

한 배열에서 다른 배열을 빼려면 아래 스 니펫을 사용하십시오.

var a1 = ['1','2','3','4','6'];
var a2 = ['3','4','5'];

var items = new Array();

items = jQuery.grep(a1,function (item) {
    return jQuery.inArray(item, a2) < 0;
});

두 번째 배열에는 존재하지 않는 첫 번째 배열의 항목 인 [ '1,'2 ','6 ']을 반환합니다.

따라서 문제 샘플에 따르면 다음 코드가 정확한 솔루션입니다.

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var _array = new Array();

_array = jQuery.grep(array2, function (item) {
     return jQuery.inArray(item, array1) < 0;
});

14

세트와 splat 연산자 (Firefox에서만 작동 할 때 호환성 표 확인 ) 가 포함 된 ES6이 도착 하면 다음과 같은 라이너 하나를 작성할 수 있습니다.

var a = ['a', 'b', 'c', 'd'];
var b = ['a', 'b'];
var b1 = new Set(b);
var difference = [...new Set([...a].filter(x => !b1.has(x)))];

결과는 [ "c", "d" ]입니다.


궁금한 점이 있다면b.filter(x => !a.indexOf(x)))
chovy

1
@ chovy 그것은 시간 복잡성이 다릅니다. 내 솔루션은 O(n + m)귀하의 솔루션이 O(n * m)n과 m이 배열의 길이 인 곳입니다. 긴 목록을 가져 오면 솔루션이 몇 초 안에 실행되지만 몇 시간이 걸립니다.
살바도르 달리

객체 목록의 속성을 비교하는 것은 어떻습니까? 이 솔루션을 사용하여 가능합니까?
chovy 2016 년

2
a.filter(x => !b1.has(x))더 간단합니다. 그리고 스펙은 복잡성이 평균적 n * f(m) + m으로 f(m)서브 리니어 일 때만 필요합니다 . 그것보다는 낫지 n * m만 반드시 그런 것은 아닙니다 n + m.
Oriol

2
@SalvadorDali var difference = [...new Set([...a].filter(x => !b1.has(x)))];왜 중복 'a'배열을 생성합니까? 왜 필터 결과를 세트로 변환 한 다음 다시 어레이로 변환합니까? 이 동일하지 않습니다var difference = a.filter(x => !b1.has(x));
디팍 미탈

13

ES2015를 통한 기능적 접근

difference두 배열 사이를 계산하는 것이 Set작업 중 하나입니다 . 이 용어 Set는 조회 속도를 높이기 위해 기본 유형을 사용해야 함을 이미 나타냅니다 . 어쨌든 두 세트의 차이를 계산할 때 세 가지 순열이 있습니다.

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

다음은 이러한 순열을 반영하는 함수형 솔루션입니다.

왼쪽 difference:

// small, reusable auxiliary functions

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


// left difference

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


// mock data

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


// run the computation

console.log( differencel(xs) (ys) );

맞다 difference:

differencer사소합니다. 그것은 그냥 differencel뒤집어 인수. 편의를 위해 함수를 작성할 수 있습니다.const differencer = flip(differencel) .. 그게 다야!

대칭 difference:

이제 우리는 왼쪽과 오른쪽을 difference가졌으므로 대칭을 구현하는 것도 간단합니다.

// small, reusable auxiliary functions

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


// left difference

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


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// mock data

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


// run the computation

console.log( difference(xs) (ys) );

이 예제는 함수형 프로그래밍의 의미에 대한 인상을 얻기위한 좋은 출발점이라고 생각합니다.

여러 가지 방법으로 서로 연결할 수있는 빌딩 블록을 사용한 프로그래밍.


12

indexOf()작은 배열 에는 솔루션을 사용하는 것이 좋지만 길이가 길어지면 알고리즘의 성능에 접근 O(n^2)합니다. 다음은 객체를 연관 배열로 사용하여 배열 항목을 키로 저장하여 매우 큰 배열에서 더 나은 성능을 발휘하는 솔루션입니다. 또한 중복 항목을 자동으로 제거하지만 문자열 값 (또는 문자열로 안전하게 저장할 수있는 값)에서만 작동합니다.

function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
arrayDiff(a1, a2); // => ['c', 'd']
arrayDiff(a2, a1); // => ['c', 'd']

객체에 대해 "for in"을 수행 할 때마다 Object.hasOwnProperty ()를 사용하려고합니다. 그렇지 않으면 기본 오브젝트의 프로토 타입에 추가 된 모든 필드를 반복 할 위험이 있습니다. (또는 객체의 부모 만) 또한 해시 테이블 생성을위한 루프와 해시 테이블을 찾는 두 개의 루프 만 필요합니다.
jholloman

1
@jholloman 나는 정중하게 동의하지 않는다 . 이제 모든 속성에 대한 열거 가능성을 제어 할 수 있으므로 열거하는 동안 얻는 속성을 포함 해야 합니다.
Phrogz

1
@Phrogz 최신 브라우저 만 걱정한다면 좋은 점입니다. 불행히도 직장에서 IE7을 다시 지원해야하므로 석기 시대는 기본 사고의 기차이며 우리는 심을 사용하지 않습니다.
jholloman 2012 년

10

Joshaven Potter의 위의 답변은 훌륭합니다. 그러나 배열 B에는 없지만 배열 C에는없는 요소를 반환합니다. 예를 들어, 그렇다면 var a=[1,2,3,4,5,6].diff( [3,4,5,7]);==> 출력 [1,2,6]하지만 출력 하지는 않습니다 [1,2,6,7] .이 둘 사이의 실제 차이입니다. 위의 포터 코드를 계속 사용할 수 있지만 비교를 거꾸로 다시 실행하면됩니다.

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return !(a.indexOf(i) > -1);});
};

////////////////////  
// Examples  
////////////////////

var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
var b=[3,4,5,7].diff([1,2,3,4,5,6]);
var c=a.concat(b);
console.log(c);

출력해야합니다 : [ 1, 2, 6, 7 ]


9

문제를 해결하는 또 다른 방법

function diffArray(arr1, arr2) {
    return arr1.concat(arr2).filter(function (val) {
        if (!(arr1.includes(val) && arr2.includes(val)))
            return val;
    });
}

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]

또한 화살표 함수 구문을 사용할 수 있습니다.

const diffArray = (arr1, arr2) => arr1.concat(arr2)
    .filter(val => !(arr1.includes(val) && arr2.includes(val)));

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]

7
Array.prototype.difference = function(e) {
    return this.filter(function(i) {return e.indexOf(i) < 0;});
};

eg:- 

[1,2,3,4,5,6,7].difference( [3,4,5] );  
 => [1, 2, 6 , 7]

이런 식으로 기본 객체를 확장해서는 안됩니다. 표준 difference이 향후 버전에서 함수로 소개 되고이 함수에 다른 함수 서명이있는 경우이 함수를 사용하는 코드 또는 외부 라이브러리가 손상됩니다.
t.niese

7

JavaScript의 필터 기능을 사용한 매우 간단한 솔루션 :

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr = arr1.concat(arr2);
  
    newArr = myArr.filter(function(item){
      return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
    });
   alert(newArr);
}

diffArray(a1, a2);


6

이건 어때요:

Array.prototype.contains = function(needle){
  for (var i=0; i<this.length; i++)
    if (this[i] == needle) return true;

  return false;
} 

Array.prototype.diff = function(compare) {
    return this.filter(function(elem) {return !compare.contains(elem);})
}

var a = new Array(1,4,7, 9);
var b = new Array(4, 8, 7);
alert(a.diff(b));

따라서이 방법으로 array1.diff(array2)차이를 얻을 수 있습니다 (알고리즘에 대한 시간 복잡성-비록 O (array1.length x array2.length))


필터 옵션을 사용하는 것이 좋습니다. 그러나 Array에 대해 contains 메소드를 작성할 필요는 없습니다. 나는 당신의 아이디어를 하나의 라이너로 변환했습니다 ... 영감을 주셔서 감사합니다!
Joshaven Potter

contains () 함수를 정의 할 필요는 없습니다. JS includes ()도 같은 기능을합니다.
Da Man

4

http://phrogz.net/JS/ArraySetMath.js 를 사용하면 다음을 수행 할 수 있습니다.

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var array3 = array2.subtract( array1 );
// ["test5", "test6"]

var array4 = array1.exclusion( array2 );
// ["test5", "test6"]

4
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

이것은 나를 위해 작동합니다


3
  • 순수한 JavaScript 솔루션 (라이브러리 없음)
  • 구형 브라우저와 호환 가능 (사용하지 않음) filter )
  • O (n ^ 2)
  • fn배열 항목을 비교하는 방법을 지정할 수있는 선택적 콜백 매개 변수

function diff(a, b, fn){
    var max = Math.max(a.length, b.length);
        d = [];
    fn = typeof fn === 'function' ? fn : false
    for(var i=0; i < max; i++){
        var ac = i < a.length ? a[i] : undefined
            bc = i < b.length ? b[i] : undefined;
        for(var k=0; k < max; k++){
            ac = ac === undefined || (k < b.length && (fn ? fn(ac, b[k]) : ac == b[k])) ? undefined : ac;
            bc = bc === undefined || (k < a.length && (fn ? fn(bc, a[k]) : bc == a[k])) ? undefined : bc;
            if(ac == undefined && bc == undefined) break;
        }
        ac !== undefined && d.push(ac);
        bc !== undefined && d.push(bc);
    }
    return d;
}

alert(
    "Test 1: " + 
    diff(
        [1, 2, 3, 4],
        [1, 4, 5, 6, 7]
      ).join(', ') +
    "\nTest 2: " +
    diff(
        [{id:'a',toString:function(){return this.id}},{id:'b',toString:function(){return this.id}},{id:'c',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        [{id:'a',toString:function(){return this.id}},{id:'e',toString:function(){return this.id}},{id:'f',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        function(a, b){ return a.id == b.id; }
    ).join(', ')
);


길이 값을 캐시하여 속도를 더 많이 줄 수 있습니다. 길이를 확인하지 않고 배열 요소에 액세스하는 것이 좋지만 간단한 확인으로 거의 100 배 속도가 향상됩니다.
Slotos

length값 을 캐시 할 이유가 없습니다 . 이미 평범한 재산입니다. jsperf.com/array-length-caching
vp_arth

3

이것은 작동합니다 : 기본적으로 두 배열을 병합하고 복제본을 찾고 복제되지 않은 것을 새로운 배열로 밀어 넣습니다.

function diff(arr1, arr2) {
  var newArr = [];
  var arr = arr1.concat(arr2);
  
  for (var i in arr){
    var f = arr[i];
    var t = 0;
    for (j=0; j<arr.length; j++){
      if(arr[j] === f){
        t++; 
        }
    }
    if (t === 1){
      newArr.push(f);
        }
  } 
  return newArr;
}


3

// es6 접근

function diff(a, b) {
  var u = a.slice(); //dup the array
  b.map(e => {
    if (u.indexOf(e) > -1) delete u[u.indexOf(e)]
    else u.push(e)   //add non existing item to temp array
  })
  return u.filter((x) => {return (x != null)}) //flatten result
}

3

대칭선형 복잡성 . ES6이 필요합니다.

function arrDiff(arr1, arr2) {
    var arrays = [arr1, arr2].sort((a, b) => a.length - b.length);
    var smallSet = new Set(arrays[0]);

    return arrays[1].filter(x => !smallSet.has(x));
}


2

생각하기 ... 도전을 위해 ;-)이 작업을 수행 할 것입니다 ... (문자열, 숫자 등의 기본 배열의 경우) 중첩 배열이 없습니다.

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

정렬은 위에서 언급 한 것과 같지 않을 수 있지만 원하는 경우 배열에서 .sort ()를 호출하여 정렬하십시오.


2

나는 오래된 배열과 새로운 배열을 가져 와서 추가 된 항목의 배열과 제거 된 항목의 배열을주는 비슷한 기능을 원했고 효율적이기를 원했습니다.

제안 된 솔루션을 http://jsbin.com/osewu3/12 에서 재생할 수 있습니다 .

누구든지 해당 알고리즘의 문제 / 개선을 볼 수 있습니까? 감사!

코드 목록 :

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // push to diff?
          r.push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // push to diff?
          a.push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}

2

다른 라이브러리를 사용하지 않는 간단한 답변을 찾고 있었고 여기에 언급되지 않은 내 자신을 생각해 냈습니다. 나는 그것이 얼마나 효율적인지 모르지만 작동합니다.

    function find_diff(arr1, arr2) {
      diff = [];
      joined = arr1.concat(arr2);
      for( i = 0; i <= joined.length; i++ ) {
        current = joined[i];
        if( joined.indexOf(current) == joined.lastIndexOf(current) ) {
          diff.push(current);
        }
      }
      return diff;
    }

내 코드의 경우 복제본도 필요하지만 항상 선호되는 것은 아닙니다.

주요 단점은 이미 거부 된 많은 옵션을 잠재적으로 비교하고 있다는 것입니다.


2

최상의 답변을위한 약간의 수정

function arr_diff(a1, a2)
{
  var a=[], diff=[];
  for(var i=0;i<a1.length;i++)
    a[a1[i]]=a1[i];
  for(var i=0;i<a2.length;i++)
    if(a[a2[i]]) delete a[a2[i]];
    else a[a2[i]]=a2[i];
  for(var k in a)
   diff.push(a[k]);
  return diff;
}

이것은 현재 유형의 요소를 고려할 것입니다. b / c a [a1 [i]]를 만들면 원래 값에서 값을 문자열로 변환하므로 실제 값을 잃었습니다.


이것은 객체 배열에 여전히 실패합니다. var a = [{a : 1}], b = [{b : 2}] arr_diff (a, b) == [].
EricP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.