자바 스크립트에서 배열 교차를위한 가장 간단한 코드


607

자바 스크립트에서 배열 교차를 구현하기위한 가장 간단한 라이브러리가없는 코드는 무엇입니까? 쓰고 싶다

intersection([1,2,3], [2,3,4,5])

그리고 얻다

[2, 3]

16
간단하거나 빠른 것을 원하십니까?
SLaks December

11
우선 순위는 간단하지만 성능이 뛰어나다는 것은 너무 치명적일 수는 없습니다 :)
Peter

4
_underscore 교차 함수를포함하여 여기의 모든 방법에 대한 JsFiddle Banchmark 테스트 페이지를 만들었습니다 . (높을수록 좋습니다) ! 여기에 이미지 설명을 입력하십시오. 지금까지 intersect_safe가 최상의 결과를 제공했습니다 . 당신과 최악의 밑줄.
neoswf

a break를 추가 Simple js loops하면 ops / sec가 ~ 10M 으로 증가
Richard

19
당신이 그것을 그리워하는 경우 : 가장 간단한 대답은 받아 들여지는 것이 아니라 바닥에있는 것입니다 : stackoverflow.com/questions/1885557/…
redben

답변:


1078

의 조합 사용 Array.prototype.filterArray.prototype.indexOf:

array1.filter(value => -1 !== array2.indexOf(value))

또는 주석에서 vrugtehagel이 제안한 것처럼 Array.prototype.includes더 간단한 코드를 위해 최신 코드를 사용할 수 있습니다 .

array1.filter(value => array2.includes(value))

이전 브라우저의 경우 :

array1.filter(function(n) {
    return array2.indexOf(n) !== -1;
});

9
배열의 프로토 타입에 라이브러리 버전을 추가하여 해결할 수 있습니다.
아논.

12
예,하지만 언급 할 가치가 있습니다.
Tim Down

18
단순성과 숫자가 아닌 숫자로 작업하기위한 최상의 답변
Muhd

41
intersection([1,2,1,1,3], [1])을 반환합니다 [1, 1, 1]. 그냥 반환해서는 안 [1]됩니까?
edjroot 2016 년

21
대신에 더 간단한 코드를 array2.indexOf(n) != -1작성할 수도 array2.includes(n)있습니다.
vrugtehagel

157

입력이 정렬되어 있다고 가정 할 경우 특히 파괴적인 것으로 보입니다.

/* destructively finds the intersection of 
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *  State of input arrays is undefined when
 *  the function returns.  They should be 
 *  (prolly) be dumped.
 *
 *  Should have O(n) operations, where n is 
 *    n = MIN(a.length, b.length)
 */
function intersection_destructive(a, b)
{
  var result = [];
  while( a.length > 0 && b.length > 0 )
  {  
     if      (a[0] < b[0] ){ a.shift(); }
     else if (a[0] > b[0] ){ b.shift(); }
     else /* they're equal */
     {
       result.push(a.shift());
       b.shift();
     }
  }

  return result;
}

비파괴는 색인을 추적해야하기 때문에 더 복잡해야합니다.

/* finds the intersection of 
 * two arrays in a simple fashion.  
 *
 * PARAMS
 *  a - first array, must already be sorted
 *  b - second array, must already be sorted
 *
 * NOTES
 *
 *  Should have O(n) operations, where n is 
 *    n = MIN(a.length(), b.length())
 */
function intersect_safe(a, b)
{
  var ai=0, bi=0;
  var result = [];

  while( ai < a.length && bi < b.length )
  {
     if      (a[ai] < b[bi] ){ ai++; }
     else if (a[ai] > b[bi] ){ bi++; }
     else /* they're equal */
     {
       result.push(a[ai]);
       ai++;
       bi++;
     }
  }

  return result;
}

14
에 많은 오류가 있습니다 intersect_safe: length메소드가 아닌 배열의 속성입니다. 에 구현되지 않은 변수 iresult.push(a[i]);있습니다. 마지막으로 이것은 일반적인 경우에는 작동하지 않습니다. >연산자 에 따라 둘 중 어느 것도 다른 객체보다 크지 않은 두 객체가 반드시 같을 필요는 없습니다. intersect_safe( [ {} ], [ {} ] )예를 들어, 앞서 언급 한 오류가 수정되면 한 요소를 가진 배열을 제공합니다.
Tim Down

1
@Tim Down : 지적한 구문 오류를 수정했습니다. 거터도 같지 않은 것을 고려하는 것이 옳거나 그른지 여부는 요구 사항에 따라 다릅니다. 원래 질문에서 내용에 배열이 포함될 것으로 예상되는 것을 눈치 채지 못했습니다. 이제 예상치 못한 입력을 처리해야한다고 말할 수는 있지만, 스펙이 이미 입력을 지시하는 경우 입력이 숫자의 배열이어야한다고 가정하면 코드는 괜찮습니다.
atk December

1
@atk : 질문의 예가 ​​숫자 만 포함하는 배열을 사용하는 것을 본다면 요점을 지적합니다.
Tim Down

4
색인을 추적하는 대신 .slice(0)에서의 복제본을 만드는 데 사용할 수도 있습니다 intersect_safe.
johnluetke

1
@ thesmart : 당신이 옳습니다. 확실히 더 많은 수행 방법이 있습니다. 이 코드는, 위, :)되지 빠르고 간단하게 의도 된
공격력

58

환경이 ECMAScript 6 Set을 지원하는 경우 간단하고 효율적인 방법 (사양 링크 참조) :

function intersect(a, b) {
  var setA = new Set(a);
  var setB = new Set(b);
  var intersection = new Set([...setA].filter(x => setB.has(x)));
  return Array.from(intersection);
}

더 짧지 만 읽기 쉽지 않습니다 (추가 교차점을 만들지 Set않음).

function intersect(a, b) {
      return [...new Set(a)].filter(x => new Set(b).has(x));
}

새로운 방지 Set에서 b모든 시간 :

function intersect(a, b) {
      var setB = new Set(b);
      return [...new Set(a)].filter(x => setB.has(x));
}

집합을 사용할 때 고유 한 값만 얻을 수 있으므로로 new Set[1,2,3,3].size평가됩니다 3.


1
[...setA]구문은 무엇입니까? 특별한 종류의 자바 스크립트 작업?
jxramos

1
Spread 구문 인 @jxramos이며이 경우 집합의 요소에서 배열을 만드는 데 사용됩니다. 이 경우 "Array.from (setA)"도 작동하지만 "간단한"이라는 질문이 있기 때문에 해당 행에서 읽을 수 있도록 더 깔끔하게 만들려고했습니다. 그 문제에서 코드가 더 간단 할 수 있다고 생각합니다. 스 니펫을 업데이트하겠습니다.
nbarbosa

@nbarbosa 궁금합니다 : 왜 어레이를 "복제"했습니까? #filter는 원래 배열을 파괴하지 않습니다. 새로운 배열을 생성합니까?
bplittle

@bplittle 중복을 제거하기 위해 세트에서 배열을 만들었습니다. 그렇지 않으면 배열을 직접 사용하면 중복이 반환됩니다. 예를 들어, 배열을 직접 사용한 경우 intersect ([1,2,2,4], [2,3])는 [2, 2]를 산출합니다.
nbarbosa

2
하지 않는 x => new Set(b).has(x)기능 차례 화살표 b집합으로 모든 이 실행의 Time (시간)을? 해당 세트를 변수에 저장해야합니다.
Aran-Fey

39

사용 Underscore.js 또는 lodash.js을

_.intersection( [0,345,324] , [1,0,324] )  // gives [0,324]

20
Op은 "라이브러리가없는"을 요청했습니다.
LinuxDisciple

@LinuxDisciple 그것을 놓친 것에 대한 나의 실수. 고마워
Sai Ram

33
어쨌든 이것은이 검색에 대한 최상위 Google 목록이므로 라이브러리 답변을 사용하는 것이 유용합니다. 감사.
webnoob

나도 이것이 게시되어 기쁘다. underscore.js의 필요성을 처음 느꼈습니다. 일반적으로 JavaScript 맵 및 파이프 라인 축소는이 작업이 아니라 우아하게 작동합니다.
Sridhar Sarnobat '11

나는 <3 밑줄과 나는 <3 Jeremy Ashkenas (그의 제작자)이지만 Lodash를 확인하는 것이 좋습니다. 기본적으로 Underscore의 우수한 버전입니다 (원래 포크였습니다). 단점은 슈퍼 최적화 (따라서 거의 읽을 수 없음) 소스 코드입니다. Underscore 사람들은 Underscore를 완전히 없애고 사람들에게 Lodash를 사용하도록 지시하는 것을 고려했지만 소스 코드 가독성에 관심이있는 사람들은 그것을 유지해야한다고 주장했습니다 (실제로 그쪽에 있었지만 이후 Lodash로 전환했습니다). @see github.com/jashkenas/underscore/issues/2182
machineghost

14

ES6 용어에 대한 나의 기여. 일반적으로 인수로 제공된 무한한 수의 배열과 배열의 교차점을 찾습니다.

Array.prototype.intersect = function(...a) {
  return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
}
var arrs = [[0,2,4,6,8],[4,5,6,7],[4,6]],
     arr = [0,1,2,3,4,5,6,7,8,9];

document.write("<pre>" + JSON.stringify(arr.intersect(...arrs)) + "</pre>");


이 코드는 훌륭하게 보이지만 완전히 이해하지는 못합니다. 설명해 주시겠습니까?
theusual

1
@novembersky 모든 주제 배열을 배열로 모은 [[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7],[4,6]]다음 적용 .reduce()합니다. 첫 번째 [0,1,2,3,4,5,6,7,8,9].filter( e => [0,2,4,6,8].includes(e)작업이 수행되고 그 결과는 새로운됩니다 pc되고 [4,5,6,7]다음 턴에 더 이상 없을 때까지 최대에 이렇게 계속 c남아 있습니다.
Redu

1
큰 데이터 세트로 작업하는 경우 비용이 많이 드는 솔루션입니다.
Madbreaks

1
prototype불필요하게 수정하지 마십시오 .
fregante

14

// Return elements of array a that are also in b in linear time:
function intersect(a, b) {
  return a.filter(Set.prototype.has, new Set(b));
}

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

큰 입력에서 다른 구현보다 우수한 간결한 솔루션을 권장합니다. 작은 입력의 성능이 중요한 경우 아래 대안을 확인하십시오.

대안 및 성능 비교 :

대체 구현에 대해서는 다음 스 니펫을 참조 하고 성능 비교는 https://jsperf.com/array-intersection-comparison 을 확인 하십시오 .

Firefox 53의 결과 :

  • 대형 어레이의 연산 / 초 (10,000 개 요소) :

    filter + has (this)               523 (this answer)
    for + has                         482
    for-loop + in                     279
    filter + in                       242
    for-loops                          24
    filter + includes                  14
    filter + indexOf                   10
  • 소형 어레이 (100 개 요소)의 Ops / sec :

    for-loop + in                 384,426
    filter + in                   192,066
    for-loops                     159,137
    filter + includes             104,068
    filter + indexOf               71,598
    filter + has (this)            43,531 (this answer)
    filter + has (arrow function)  35,588

2
intersect([1,2,2,3], [2,3,4,5])을 반환합니다 [2, 2, 3].
SeregPie

1
@SeregPie 정확합니다. 코멘트에 따르면 "b에있는 배열 a의 요소를 반환"
le_m

그러나 품질 답변, 그러나 세트의 사용은 op의 질문이 배열 교차에 대해서만 질문하고 복제본을 처리하는 방법에 대한 언급 / 설명을하지 않기 때문에 근본적으로 결과를 변경합니다. 부끄러워서,이 답변은 중복이 존재할 때 예기치 않은 결과를 초래할 수 있습니다.
Madbreaks

1
마음에 들지만 "필터 + 포함"으로 불필요한 기능을 추가했습니다. 시도하십시오 a.filter(b.includes). 상당히 빨리 실행되어야합니다 (기능 업그레이드와 동일).
SEoF

11

연관 배열을 사용하는 것은 어떻습니까?

function intersect(a, b) {
    var d1 = {};
    var d2 = {};
    var results = [];
    for (var i = 0; i < a.length; i++) {
        d1[a[i]] = true;
    }
    for (var j = 0; j < b.length; j++) {
        d2[b[j]] = true;
    }
    for (var k in d1) {
        if (d2[k]) 
            results.push(k);
    }
    return results;
}

편집하다:

// new version
function intersect(a, b) {
    var d = {};
    var results = [];
    for (var i = 0; i < b.length; i++) {
        d[b[i]] = true;
    }
    for (var j = 0; j < a.length; j++) {
        if (d[a[j]]) 
            results.push(a[j]);
    }
    return results;
}

1
배열에 문자열이나 숫자 만 포함되어 있고 페이지의 스크립트가 엉망이 아닌 경우에만 가능성이 있습니다 Object.prototype.
Tim Down

2
OP의 예제는 숫자를 사용했으며 스크립트가 Object.prototype을 망친 경우 스크립트를 다시 작성하거나 제거해야합니다.
Steven Huwig 2009

(d1)과 (d2)가 필요하지 않습니다. (d2)를 만든 다음 (d1)을 반복하는 대신 (a)를 반복합니다.
StanleyH

d[b[i]] = true;대신 d[b[j]] = true;( i아닌 j) 이어야 합니다 . 그러나 편집에는 6자가 필요합니다.
Izhaki

@Izhaki 감사합니다. (최소 편집 요구 사항을 해결하기 위해 // 주석이 추가되었습니다.)
Steven Huwig

8
  1. 그것을 정렬
  2. 인덱스 0에서 하나씩 확인하고 그로부터 새 배열을 만듭니다.

이런 식으로 잘 테스트되지는 않았습니다.

function intersection(x,y){
 x.sort();y.sort();
 var i=j=0;ret=[];
 while(i<x.length && j<y.length){
  if(x[i]<y[j])i++;
  else if(y[j]<x[i])j++;
  else {
   ret.push(x[i]);
   i++,j++;
  }
 }
 return ret;
}

alert(intersection([1,2,3], [2,3,4,5]));

추신 : 알고리즘은 숫자 및 일반 문자열에만 사용되며 임의의 객체 배열의 교차가 작동하지 않을 수 있습니다.


3
정렬이 임의의 객체 배열에 반드시 도움이되는 것은 아닙니다.
Tim Down

배열이 정렬되지 않은 경우 1000 길이 배열 x 1000 길이 배열을 교차 할 때 약 1,000,000 회 반복해야합니다.
YOU

내 요점을 놓친 것 같습니다. JavaScript의 임의의 객체에는 자연스러운 정렬 순서가 없으므로 임의의 객체 배열을 정렬해도 동일한 객체가 그룹화되지 않습니다. 작동하지 않는 효율적인 알고리즘을 갖는 것은 좋지 않습니다.
Tim Down

아 죄송합니다. "임의의 물건"을 놓쳤습니다. 맞습니다. 해당 객체는 정렬 할 수 없으며 알고리즘이 작동하지 않을 수 있습니다.
당신은

8

정렬 된 프리미티브 배열에 대한 @atk의 구현 성능은 .shift가 아닌 .pop을 사용하여 향상시킬 수 있습니다.

function intersect(array1, array2) {
   var result = [];
   // Don't destroy the original arrays
   var a = array1.slice(0);
   var b = array2.slice(0);
   var aLast = a.length - 1;
   var bLast = b.length - 1;
   while (aLast >= 0 && bLast >= 0) {
      if (a[aLast] > b[bLast] ) {
         a.pop();
         aLast--;
      } else if (a[aLast] < b[bLast] ){
         b.pop();
         bLast--;
      } else /* they're equal */ {
         result.push(a.pop());
         b.pop();
         aLast--;
         bLast--;
      }
   }
   return result;
}

jsPerf를 사용하여 벤치 마크를 만들었습니다 : http://bit.ly/P9FrZK . .pop을 사용하면 약 3 배 더 빠릅니다.


1
다른 사람들을위한 보조 메모처럼 문자열이 아닌 숫자에만 작동합니다.
Izhaki

당신이 대체 할 경우주의 a[aLast] > b[bLast]a[aLast].localeCompare(b[bLast]) > 0(과와 같은 else if아래) 다음이 문자열에서 작동합니다.
Andrew

1
속도 차이 .pop는 O (1)이고 .shift()O (n) 이므로 어레이의 크기에 따라 달라집니다
Esailija

8

jQuery 사용 :

var a = [1,2,3];
var b = [2,3,4,5];
var c = $(b).not($(b).not(a));
alert(c);

8
이것은로도 쓸 수 c = $(b).filter(a);있지만 설명서에서는 요소에 대해서만 작동한다고 언급하기 때문에 이런 종류의 배열 조작에 jQuery를 사용하지 않는 것이 좋습니다.
Stryner

1
이것은 op의 질문에 대답하지 않습니다 : "가장 간단한 라이브러리가없는 코드 는 무엇입니까 ?"
Madbreaks

7

문자열이나 숫자 만 포함하는 배열의 경우 다른 답변 중 일부에 따라 정렬하여 무언가를 수행 할 수 있습니다. 임의의 객체 배열의 일반적인 경우에는 먼 길을 피할 수 없다고 생각합니다. 다음은 매개 변수로 제공된 여러 배열의 교차점을 제공합니다 arrayIntersection.

var arrayContains = Array.prototype.indexOf ?
    function(arr, val) {
        return arr.indexOf(val) > -1;
    } :
    function(arr, val) {
        var i = arr.length;
        while (i--) {
            if (arr[i] === val) {
                return true;
            }
        }
        return false;
    };

function arrayIntersection() {
    var val, arrayCount, firstArray, i, j, intersection = [], missing;
    var arrays = Array.prototype.slice.call(arguments); // Convert arguments into a real array

    // Search for common values
    firstArray = arrays.pop();
    if (firstArray) {
        j = firstArray.length;
        arrayCount = arrays.length;
        while (j--) {
            val = firstArray[j];
            missing = false;

            // Check val is present in each remaining array 
            i = arrayCount;
            while (!missing && i--) {
                if ( !arrayContains(arrays[i], val) ) {
                    missing = true;
                }
            }
            if (!missing) {
                intersection.push(val);
            }
        }
    }
    return intersection;
}

arrayIntersection( [1, 2, 3, "a"], [1, "a", 2], ["a", 1] ); // Gives [1, "a"]; 

이것은 객체 동일성이 유일한 형태의 평등 인 경우에만 작동합니다.
Steven Huwig 2009

네,하지만 대부분의 사람들에게는 이것이 자연스러워 보입니다. 다른 동등성 테스트를 수행하기 위해 대체 함수를 연결하는 것도 간단합니다.
Tim Down

귀하의 예제에서 실수로 전역 변수 firstArr을 생성한다고 생각합니다.
Jason Jackson

@JasonJackson : 그렇습니다, 감사합니다. 변수를 호출할지 firstArr또는 firstArray모든 참조를 업데이트하지 않았는 지에 대한 내 마음을 분명히 바꿨습니다 . 결정된.
Tim Down

7

ES2015와 Sets를 사용하면 꽤 짧습니다. 문자열과 같은 배열 형 값을 허용하고 중복을 제거합니다.

let intersection = function(a, b) {
  a = new Set(a), b = new Set(b);
  return [...a].filter(v => b.has(v));
};

console.log(intersection([1,2,1,2,3], [2,3,5,4,5,3]));

console.log(intersection('ccaabbab', 'addb').join(''));


와 배열에 설정에서 변환 [... A] 중복 항목, 좋은 생각, 감사 제거
V-SHY

1
이 솔루션은 귀하에게 두 번 제공되었습니다.
Madbreaks

7

당신은을 사용할 수 있습니다 SetthisArgArray#filter및 걸릴 Set#has콜백한다.

function intersection(a, b) {
    return a.filter(Set.prototype.has, new Set(b));
}

console.log(intersection([1, 2, 3], [2, 3, 4, 5]));


왜 이것이 더 많은 표를 얻지 못했는지 모르겠습니다. 분명히 가장 좋은 대답입니다.
Paul Rooney

5

JavaScript 객체를 사용하여 배열 중 하나에서 값의 색인을 작성하는 가장 작은 것 (여기서 filter / indexOf 솔루션 ) 을 약간 조정하면 O (N * M)에서 "아마도"선형 시간으로 줄입니다. 소스 1 소스 2

function intersect(a, b) {
  var aa = {};
  a.forEach(function(v) { aa[v]=1; });
  return b.filter(function(v) { return v in aa; });
}

이것은 가장 간단한 해결책이 아니며 ( filter + indexOf 보다 더 많은 코드 ), 가장 빠르지도 않습니다 (아마 intersect_safe () 보다 상수 요소에 의해 느려질 수도 있음 ).하지만 꽤 좋은 균형처럼 보입니다. 그것은에 매우 좋은 성능을 제공하고 사전 분류 입력을 필요로하지 않는 동안, 간단한 쪽.


5

한 번에 여러 개의 배열을 처리 할 수있는 또 다른 인덱스 접근 방식 :

// Calculate intersection of multiple array or object values.
function intersect (arrList) {
    var arrLength = Object.keys(arrList).length;
        // (Also accepts regular objects as input)
    var index = {};
    for (var i in arrList) {
        for (var j in arrList[i]) {
            var v = arrList[i][j];
            if (index[v] === undefined) index[v] = 0;
            index[v]++;
        };
    };
    var retv = [];
    for (var i in index) {
        if (index[i] == arrLength) retv.push(i);
    };
    return retv;
};

문자열로 평가할 수있는 값에 대해서만 작동하며 다음과 같은 배열로 전달해야합니다.

intersect ([arr1, arr2, arr3...]);

...하지만 객체를 매개 변수 또는 교차 할 요소로 투명하게 수용합니다 (항상 공통 값의 배열을 반환합니다). 예 :

intersect ({foo: [1, 2, 3, 4], bar: {a: 2, j:4}}); // [2, 4]
intersect ([{x: "hello", y: "world"}, ["hello", "user"]]); // ["hello"]

편집하다: 나는 이것이 약간의 버그가 있음을 알았습니다.

즉 : 입력 배열 자체에는 반복이 포함될 수 없다고 생각했습니다 (제공된 예에서는 그렇지 않음).

그러나 입력 배열에 반복이 포함되면 잘못된 결과가 생성됩니다. 예 (아래 구현 사용) :

intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]);
// Expected: [ '1' ]
// Actual: [ '1', '3' ]

다행히도 이는 단순히 2 단계 색인을 추가하여 쉽게 해결할 수 있습니다. 그건:

변화:

        if (index[v] === undefined) index[v] = 0;
        index[v]++;

으로:

        if (index[v] === undefined) index[v] = {};
        index[v][i] = true; // Mark as present in i input.

...과:

         if (index[i] == arrLength) retv.push(i);

으로:

         if (Object.keys(index[i]).length == arrLength) retv.push(i);

완전한 예 :

// Calculate intersection of multiple array or object values.
function intersect (arrList) {
    var arrLength = Object.keys(arrList).length;
        // (Also accepts regular objects as input)
    var index = {};
    for (var i in arrList) {
        for (var j in arrList[i]) {
            var v = arrList[i][j];
            if (index[v] === undefined) index[v] = {};
            index[v][i] = true; // Mark as present in i input.
        };
    };
    var retv = [];
    for (var i in index) {
        if (Object.keys(index[i]).length == arrLength) retv.push(i);
    };
    return retv;
};

intersect ([[1, 3, 4, 6, 3], [1, 8, 99]]); // [ '1' ]

2
이것은 작은 수정으로 가장 좋은 대답입니다. 애프터 var v = 줄을 추가 if (typeof v == 'function') continue;하고 그 결과에 기능을 추가 건너 뜁니다. 감사!
Zsolti

감사합니다 @Zsolti. 함수 (및 우리가 처리하려는 방식)가 원래 질문의 범위를 벗어 났기 때문에 귀하의 제안을 추가하지 않습니다. 그러나 내 편집을 참조하십시오 : 입력 배열에 반복이있을 수 있다면 원래 구현은 버그가 있습니다. 편집에서 수정했습니다. ... 반면, 반복이 없다는 것을 확신하면 원래 구현이 약간 저렴합니다.
bitifet

... 함수에 대해서도 교차 할 수 있습니다. @Zsolti가 말한 것처럼 (로 if (typeof v == 'function'), 문자열 화 ( v.toString())를 색인의 키로 사용할 수 있지만 그대로 유지하려면 무언가를해야합니다. 이렇게하는 가장 쉬운 방법은이 경우에, 최신 deindexaton도이 조건을 감지하고 적절한 값 (기능)을 복원하기 위해 변경해야하는 대신 간단한 부울 진정한 가치의 값으로 원래의 기능을 할당 간단하지만..
bitifet

100 개의 요소를 가진 30 개의 배열로 얼마나 빠를 수 있습니까? CPU 사용량은 어떻습니까?
aidonsnous

5

IE를 제외한 모든 브라우저에서 사용할 수 있습니다.

const intersection = array1.filter(element => array2.includes(element));

또는 IE의 경우 :

const intersection = array1.filter(element => array2.indexOf(element) !== -1);

기능으로 바꿀 수 있다면 좋을 것입니다
avalanche1

@ avalanche1 const 교차 = (a1, a2) => a1.filter (e => a2.includes (e));
jota3

4
function intersection(A,B){
var result = new Array();
for (i=0; i<A.length; i++) {
    for (j=0; j<B.length; j++) {
        if (A[i] == B[j] && $.inArray(A[i],result) == -1) {
            result.push(A[i]);
        }
    }
}
return result;
}

4

데이터에 약간의 제한이 있으므로 선형으로 수행 할 수 있습니다 시간으로 !

내용은 양의 정수 :는 "본 / 보이지 않는"부울에 값을 매핑 배열을 사용합니다.

function intersectIntegers(array1,array2) { 
   var seen=[],
       result=[];
   for (var i = 0; i < array1.length; i++) {
     seen[array1[i]] = true;
   }
   for (var i = 0; i < array2.length; i++) {
     if ( seen[array2[i]])
        result.push(array2[i]);
   }
   return result;
}

객체에 대해서도 비슷한 기술이 있습니다 . 더미 키를 가져 와서 array1의 각 요소에 대해 "true"로 설정 한 다음 array2의 요소에서이 키를 찾으십시오. 완료되면 정리하십시오.

function intersectObjects(array1,array2) { 
   var result=[];
   var key="tmpKey_intersect"
   for (var i = 0; i < array1.length; i++) {
     array1[i][key] = true;
   }
   for (var i = 0; i < array2.length; i++) {
     if (array2[i][key])
        result.push(array2[i]);
   }
   for (var i = 0; i < array1.length; i++) {
     delete array1[i][key];
   }
   return result;
}

물론 키가 이전에 나타나지 않았는지 확인해야합니다. 그렇지 않으면 데이터가 손상 될 수 있습니다.


그건 그렇고, 이것은 여러 배열을 교차하도록 쉽게 확장 될 수 있습니다. 부울을 정수로 바꾸고 볼 때마다 증가합니다. 마지막 라운드에서 교차점을 쉽게 읽을 수 있습니다.
tarulen

재미있는 해결책입니다. 대부분의 다른 솔루션은 O (n ^ 2)이지만 이것은 O (n)입니다. 정수 코드를 ericP의 성능 바이올린 여기에 jsfiddle.net/321juyLu/2에 추가했습니다 . 그것은 3 번째, 나
처럼 생겼다

3

나는 나에게 가장 잘 맞는 것에 공헌 할 것이다.

if (!Array.prototype.intersect){
Array.prototype.intersect = function (arr1) {

    var r = [], o = {}, l = this.length, i, v;
    for (i = 0; i < l; i++) {
        o[this[i]] = true;
    }
    l = arr1.length;
    for (i = 0; i < l; i++) {
        v = arr1[i];
        if (v in o) {
            r.push(v);
        }
    }
    return r;
};
}

3

IE 9.0, chrome, firefox, opera, "indexOf",

    function intersection(a,b){
     var rs = [], x = a.length;
     while (x--) b.indexOf(a[x])!=-1 && rs.push(a[x]);
     return rs.sort();
    }

intersection([1,2,3], [2,3,4,5]);
//Result:  [2,3]

2

'use strict'

// Example 1
function intersection(a1, a2) {
    return a1.filter(x => a2.indexOf(x) > -1)
}

// Example 2 (prototype function)
Array.prototype.intersection = function(arr) {
    return this.filter(x => arr.indexOf(x) > -1)
} 

const a1 = [1, 2, 3]
const a2 = [2, 3, 4, 5]

console.log(intersection(a1, a2))
console.log(a1.intersection(a2))


2

ES2015를 통한 기능적 접근

기능적 접근 방식은 부작용없이 순수한 기능 만 사용하는 것을 고려해야하며, 각 기능은 단일 작업에만 관련됩니다.

이러한 제한은 관련된 기능의 구성 성과 재사용 성을 향상시킵니다.

// small, reusable auxiliary functions

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


// intersection

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


// mock data

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


// run it

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

Set조회 유형이 유리한 기본 유형이 사용됩니다.

중복 방지

분명히 첫 번째 항목에서 반복적으로 발생하는 항목 Array은 유지되고 두 번째 항목 Array은 중복 제거됩니다. 원하는 동작 일 수도 있고 아닐 수도 있습니다. 고유 한 결과가 필요한 경우 dedupe첫 번째 인수 에만 적용 하십시오.

// auxiliary functions

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


// intersection

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


// de-duplication

const dedupe = comp(afrom) (createSet);


// mock data

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


// unique result

console.log( intersect(dedupe(xs)) (ys) );

임의의 수의 교점을 계산 Arrays

당신의 임의의 수의 교차점 계산하려면 ArrayS를 단지 구성 intersect으로 foldl. 다음은 편리한 기능입니다.

// auxiliary functions

const apply = f => x => f(x);
const uncurry = f => (x, y) => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);


// intersection

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


// intersection of an arbitrarily number of Arrays

const intersectn = (head, ...tail) => foldl(intersect) (head) (tail);


// mock data

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


// run

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


인상적인 기능성 : Haskell이 아닌 것을 확인하기 위해 두 번 복용해야했습니다. 유일한 nitpick은 : (expr ? true : false)중복입니다. expr실제 부울이 필요하지 않고 진실 / 거짓 일 경우에만 사용하십시오 .
jose_castro_arnaud

2

간단하게하기 위해 :

// Usage
const intersection = allLists
  .reduce(intersect, allValues)
  .reduce(removeDuplicates, []);


// Implementation
const intersect = (intersection, list) =>
  intersection.filter(item =>
    list.some(x => x === item));

const removeDuplicates = (uniques, item) =>
  uniques.includes(item) ? uniques : uniques.concat(item);


// Example Data
const somePeople = [bob, doug, jill];
const otherPeople = [sarah, bob, jill];
const morePeople = [jack, jill];

const allPeople = [...somePeople, ...otherPeople, ...morePeople];
const allGroups = [somePeople, otherPeople, morePeople];

// Example Usage
const intersection = allGroups
  .reduce(intersect, allPeople)
  .reduce(removeDuplicates, []);

intersection; // [jill]

혜택:

  • 간단한 흙
  • 데이터 중심
  • 임의의 수의 목록에 작동
  • 임의의 길이의 목록에서 작동
  • 임의의 유형의 값에 작동
  • 임의의 정렬 순서로 작동
  • 모양 유지
  • 가능한 경우 일찍 나가다
  • 메모리 안전, 기능 / 배열 프로토 타입을 통한 탬 퍼링 부족

단점 :

  • 더 높은 메모리 사용량
  • 더 높은 CPU 사용량
  • 감소에 대한 이해가 필요하다
  • 데이터 흐름에 대한 이해가 필요합니다

이것을 3D 엔진 또는 커널 작업에 사용하고 싶지는 않지만 이벤트 기반 앱에서 실행하는 데 문제가 있으면 디자인에 더 큰 문제가 있습니다.


2

.reduce지도를 만들고 .filter교차로를 찾습니다. delete내에서 .filter두 번째 배열을 고유 한 세트처럼 취급 할 수 있습니다.

function intersection (a, b) {
  var seen = a.reduce(function (h, k) {
    h[k] = true;
    return h;
  }, {});

  return b.filter(function (k) {
    var exists = seen[k];
    delete seen[k];
    return exists;
  });
}

이 접근법은 추론하기가 매우 쉽습니다. 일정한 시간에 수행됩니다.


2

이것은 아마도 list1.filter (n => list2.includes (n)) 외에 가장 간단한 것입니다.

var list1 = ['bread', 'ice cream', 'cereals', 'strawberry', 'chocolate']
var list2 = ['bread', 'cherry', 'ice cream', 'oats']

function check_common(list1, list2){
	
	list3 = []
	for (let i=0; i<list1.length; i++){
		
		for (let j=0; j<list2.length; j++){	
			if (list1[i] === list2[j]){
				list3.push(list1[i]);				
			}		
		}
		
	}
	return list3
	
}

check_common(list1, list2) // ["bread", "ice cream"]


이것은 O (nm) 시간 복잡성
을가집니다

2

교차하는 여러 배열을 처리 해야하는 경우 :

const intersect = (a, b, ...rest) => {
  if (rest.length === 0) return [...new Set(a)].filter(x => new Set(b).has(x));
  return intersect(a, intersect(b, ...rest));
};

console.log(intersect([1,2,3,4,5], [1,2], [1, 2, 3,4,5], [2, 10, 1])) // [1,2]


그러나 100 개의 요소를 가진 30 개의 배열에 대한이 솔루션은 얼마나 빠릅니까?
aidonsnous

이것은 자바 스크립트 메소드에만 국한되지 않고 코드가 실행될 VM은 최대한 멀리 최적화 할 수 있습니다. 이 의견의 연령에 비해 최신 버전의 V8에서이를 실행하면 더 빠른 솔루션이 없다고 확신합니다.
Belfordz

2

ES6 스타일의 간단한 방법.

const intersection = (a, b) => {
  const s = new Set(b);
  return a.filter(x => s.has(x));
};

예:

intersection([1, 2, 3], [4, 3, 2]); // [2, 3]

2

객체의 특정 속성을 기반으로 객체 배열의 교차를 감지 할 수있는 통합 함수를 작성했습니다.

예를 들어

if arr1 = [{id: 10}, {id: 20}]
and arr2 =  [{id: 20}, {id: 25}]

그리고 우리는 id속성을 기반으로 교차를 원한다면 출력은 다음과 같아야합니다.

[{id: 20}]

따라서 동일한 기능 (참고 : ES6 코드)은 다음과 같습니다.

const intersect = (arr1, arr2, accessors = [v => v, v => v]) => {
    const [fn1, fn2] = accessors;
    const set = new Set(arr2.map(v => fn2(v)));
    return arr1.filter(value => set.has(fn1(value)));
};

함수를 다음과 같이 호출 할 수 있습니다.

intersect(arr1, arr2, [elem => elem.id, elem => elem.id])

참고 :이 함수는 첫 번째 배열이 기본 배열이므로 교차 결과는 기본 배열의 교차 결과임을 고려하여 교차점을 찾습니다.


2

map.has ()가 ~ O (1)라고 가정하면 O (array1 + array2) 시간이 더 빠를 것이라고 생각하십시오. 잘못되면 수정하십시오.

const intersection = (a1, a2) => {
  let map = new Map();
  let result = []
  for (let i of a1) {
    if (!map.has(i)) map.set(i, true);
  }
  for (let i of a2) {
    if (map.has(i)) result.push(i)
  }
  return result;
}


1

underscore.js 구현 은 다음과 같습니다 .

_.intersection = function(array) {
  if (array == null) return [];
  var result = [];
  var argsLength = arguments.length;
  for (var i = 0, length = array.length; i < length; i++) {
    var item = array[i];
    if (_.contains(result, item)) continue;
    for (var j = 1; j < argsLength; j++) {
      if (!_.contains(arguments[j], item)) break;
    }
    if (j === argsLength) result.push(item);
  }
  return result;
};

출처 : http://underscorejs.org/docs/underscore.html#section-62


undesrcore를 사용할 수있는 경우 나쁜 참조는 아닙니다
Dimitrios Mistriotis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.