programing

여러 JavaScript 배열 간 일치 항목 찾기

testmans 2023. 11. 6. 21:42
반응형

여러 JavaScript 배열 간 일치 항목 찾기

저는 문자열 값을 가진 배열을 여러 개 가지고 있는데 그것들을 비교해서 모든 배열 간에 일치하는 결과만 유지하고 싶습니다.

이 예제 코드는 다음과 같습니다.

var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2 = ['taco', 'fish', 'apple', 'pizza'];
var arr3 = ['banana', 'pizza', 'fish', 'apple'];

주어진 모든 배열에서 일치하는 내용이 포함된 다음 배열을 제작하고자 합니다.

['apple', 'fish', 'pizza']

모든 어레이를 통합할 수 있다는 것을 알고 있습니다.var newArr = arr1.concat(arr2, arr3);하지만 그것은 나에게 모든 것과 중복되는 것들이 있는 배열을 제공할 뿐입니다.언더스코어.js와 같은 라이브러리의 오버헤드 없이 쉽게 수행할 수 있습니까?

(좋아요, 그리고 이제 저도 배고파요!)

편집 저는 단지 3개의 어레이를 예로 들었을 뿐인데, 알 수 없는 양의 어레이가 있을 수 있다는 것을 언급해야 할 것 같습니다.

var result = arrays.shift().filter(function(v) {
    return arrays.every(function(a) {
        return a.indexOf(v) !== -1;
    });
});

데모: http://jsfiddle.net/nWjcp/2/

처음에 가장 짧은 배열을 얻기 위해 외부 배열을 먼저 정렬할 수 있습니다...

arrays.sort(function(a, b) {
    return a.length - b.length;
});

완성도를 위해 어레이의 중복을 다루는 솔루션이 있습니다.사용합니다..reduce()대신에.filter()...

var result = arrays.shift().reduce(function(res, v) {
    if (res.indexOf(v) === -1 && arrays.every(function(a) {
        return a.indexOf(v) !== -1;
    })) res.push(v);
    return res;
}, []);

데모: http://jsfiddle.net/nWjcp/4/

교차점을 찾고자 하는 배열이 있다고 가정할 때, 가장 간단한 단일 라이너 접근법은

var arr = [[0,1,2,3,4,5,6,7,8,9],[0,2,4,6,8],[4,5,6,7]],
    int = arr.reduce((p,c) => p.filter(e => c.includes(e)));

document.write("<pre>" + JSON.stringify(int) + "</pre>");

질문에 불특정 수의 배열을 추가했으므로 각 항목에 대한 카운트를 개체로 수집한 다음 최대 카운트를 가지는 항목을 수집하는 다른 방법이 있습니다.

이 접근 방식의 장점:

  1. 어레이 크기가 더 큰 경우 검색 옵션(다른 답변에서 사용)보다 최대 15배 빠름
  2. ES5 또는 ES5 shim 필요 없음(모든 브라우저에서 작동)
  3. 완전 비파괴(소스 데이터를 전혀 변경하지 않음)
  4. 소스 배열에서 중복 항목을 처리
  5. 임의 수의 입력 배열을 처리합니다.

여기 암호가 있습니다.

function containsAll(/* pass all arrays here */) {
    var output = [];
    var cntObj = {};
    var array, item, cnt;
    // for each array passed as an argument to the function
    for (var i = 0; i < arguments.length; i++) {
        array = arguments[i];
        // for each element in the array
        for (var j = 0; j < array.length; j++) {
            item = "-" + array[j];
            cnt = cntObj[item] || 0;
            // if cnt is exactly the number of previous arrays, 
            // then increment by one so we count only one per array
            if (cnt == i) {
                cntObj[item] = cnt + 1;
            }
        }
    }
    // now collect all results that are in all arrays
    for (item in cntObj) {
        if (cntObj.hasOwnProperty(item) && cntObj[item] === arguments.length) {
            output.push(item.substring(1));
        }
    }
    return(output);
}    

작업 데모: http://jsfiddle.net/jfriend00/52mAP/

참고로, 이것은 ES5를 필요로 하지 않기 때문에 심이 없는 모든 브라우저에서 작동할 것입니다.

각 1000개 길이의 15개 어레이에 대한 성능 테스트에서는 이 jsperf: http://jsperf.com/in-all-arrays 에서 amnot i am의 답변에 사용된 검색 방법보다 10배 이상 빨랐습니다.


여기 ES6를 사용하는 버전이 있습니다.Map그리고.Set정보를 수집하고 추적할 수 있습니다.이는 데이터 유형이 보존되고 무엇이든 될 수 있다는 장점이 있습니다(자연스러운 문자열 변환이 필요하지도 않고 객체가 동일한 객체이며 속성/값이 동일하지 않은 것으로 비교되지만 데이터는 객체가 될 수도 있습니다.

var arrays = [
    ['valueOf', 'toString','apple', 'orange', 'banana', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza', 1, 2, 999, 888],
    ['valueOf', 'toString','taco', 'fish', 'fish', 'apple', 'pizza', 1, 999, 777, 999, 1],
    ['valueOf', 'toString','banana', 'pizza', 'fish', 'apple', 'apple', 1, 2, 999, 666, 555]
    ];
    
// subclass for updating cnts    
class MapCnt extends Map {
    constructor(iterable) {
        super(iterable);
    }
    
    cnt(iterable) {
        // make sure items from the array are unique
        let set = new Set(iterable);
        // now update the cnt for each item in the set
        for (let item of set) {
            let cnt = this.get(item) || 0;
            ++cnt;
            this.set(item, cnt);
        }
    }
}


function containsAll(...allArrays) {
    let cntObj = new MapCnt();
    for (array of allArrays) {
        cntObj.cnt(array);
    }
    // now see how many items have the full cnt
    let output = [];
    for (var [item, cnt] of cntObj.entries()) {
        if (cnt === allArrays.length) {
            output.push(item);
        }
    }
    return(output);
}    

var result = containsAll.apply(this, arrays);

document.body.innerHTML = "<pre>[<br>    " + result.join(',<br>    ') + "<br>]</pre>";

몇 가지 생각: 가장 짧은 배열의 항목만 비교할 수 있고, 반환되는 배열의 중복을 방지할 수 있습니다.

function arraysInCommon(arrays){
    var i, common,
    L= arrays.length, min= Infinity;
    while(L){
        if(arrays[--L].length<min){
            min= arrays[L].length;
            i= L;
        }
    }
    common= arrays.splice(i, 1)[0];
    return common.filter(function(itm, indx){
        if(common.indexOf(itm)== indx){
            return arrays.every(function(arr){
                return arr.indexOf(itm)!= -1;
            });
        }
    });
}

var arr1= ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2= ['taco', 'fish', 'apple', 'pizza', 'apple','apple'];
var arr3= ['banana', 'pizza', 'fish', 'apple','fish'];

var allArrays = [arr1,arr2,arr3];

arraysInCommon(allArrays).sort();

반환된 값:apple,fish,pizza

데모 - http://jsfiddle.net/kMcud/

    // The easiest way!! 
    
    var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
    var arr2 = ['taco', 'fish', 'apple', 'pizza'];
    var arr3 = ['banana', 'pizza', 'fish', 'apple'];
    var arr4 = [];


    for(let i of arr1){
      if(arr2.includes(i) && arr3.includes(i)){
        arr4.push(i)
      }
    }

    console.log(arr4)


------------- OR -----------------


arr4 = arr1.filter(value => arr2.includes(value) && arr3.includes(value))

어레이의 어레이를 가정하고 모든 어레이를 확인하는 방법:

데모: http://jsfiddle.net/qUQHW/

var tmp = {};
for (i = 0; i < data.length; i++) {
    for (j = 0; j < data[i].length; j++) {
        if (!tmp[data[i][j]]) {
            tmp[data[i][j]] = 0;
        }
        tmp[data[i][j]]++;
    }
}

var results = $.map(tmp, function(val,key) {
    return val == data.length ? key :null;
})

여기 한 줄 솔루션이 있습니다.두 가지 생각 단계로 나눌 수 있습니다.

  1. 두 배열 간 결합/교차 계산

var arrA = [1,2,3,4,5];
var arrB = [4,5,10];
var innerJoin = arrA.filter(el=>arrB.includes(el));
console.log(`Intersection is: ${innerJoin}`);

  1. 내용 축소: 누적 교차점과 다음 배열 사이의 교차점을 계산합니다.

var arrays = [
 ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'],
 ['taco', 'fish', 'apple', 'pizza'],
 ['banana', 'pizza', 'fish', 'apple']
];
var join = arrays.reduce((join, current) => join.filter(el => current.includes(el)));
console.log(`Intersection is: ${join}`);

이는 모든 수의 배열에 대해 작동해야 합니다.

function intersection(arr1, arr2) {
  var temp = [];

  for (var i in arr1) {
    var element = arr1[i];

    if (arr2.indexOf(element) > -1) {
      temp.push(element);
    }
  }

  return temp;
}

function multi_intersect() {
  var arrays = Array.prototype.slice.apply(arguments).slice(1);
  var temp = arguments[0];

  for (var i in arrays) {
    temp = intersection(arrays[i], temp);

    if (temp == []) {
      break;
    }
  }

  return temp;
}

var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2 = ['taco', 'fish', 'apple', 'pizza'];
var arr3 = ['banana', 'pizza', 'fish', 'apple'];

multi_intersect(arr1, arr2, arr3);

단지 그것을 위해, 또 다른 긴 손 접근법:

function getCommon(a) {

  // default result is copy of first array
  var result = a[0].slice();
  var mem, arr, found = false;

  // For each member of result, see if it's in all other arrays
  // Go backwards so can splice missing entries
  var i = result.length;

  while (i--) {
    mem = result[i];

    // Check in each array
    for (var j=1, jLen=a.length; j<jLen; j++) {
      arr = a[j];
      found = false;

      // For each member of arr and until found
      var k = arr.length;
      while (k-- && !found) {

        // If found in this array, set found to true
        if (mem == arr[k]) {
          found = true;
        }
      }
      // if word wasn't found in this array, remove it from result and 
      // start on next member of result, skip remaining arrays.
      if (!found) {
        result.splice(i,1);
        break;
      }
    }
  }
  return result;
}

var data = [
  ['taco', 'fish', 'apple', 'pizza', 'mango', 'pear'],
  ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'],
  ['banana', 'pizza', 'fish', 'apple'],
  ['banana', 'pizza', 'fish', 'apple', 'mango', 'pear']
];

편집

Object.prototype에서 이를 기준으로 열거할 수 없는 속성을 찾는 함수:

// Return an array of Object.prototype property names that are not enumerable
// even when added directly to an object.
// Can be helpful with IE as properties like toString are not enumerable even
// when added to an object.
function getNeverEnumerables() {

    // List of Object.prototype property names plus a random name for testing
    var spNames = 'constructor toString toLocaleString valueOf ' +
                  'hasOwnProperty isPrototypeOf propertyIsEnumerable foo';

    var spObj = {foo:'', 'constructor':'', 'toString':'', 'toLocaleString':'', 'valueOf':'',
                 'hasOwnProperty':'', 'isPrototypeOf':'', 'propertyIsEnumerable':''};

    var re = [];

    // BUild list of enumerable names in spObj
    for (var p in spObj) {
      re.push(p); 
    }

    // Remove enumerable names from spNames and turn into an array
    re = new RegExp('(^|\\s)' + re.join('|') + '(\\s|$)','g');
    return spNames.replace(re, ' ').replace(/(^\s+)|\s\s+|(\s+$)/g,'').split(' ');
}

document.write(getNeverEnumerables().join('<br>'));

이것은 기본적으로 요약된 모든 답변의 모음집입니다.

	 // Intersect any number of arrays:

	function intersect() {

	  // - Arguments -> traditional array,
	  // - First item ( arrays[0] ) = shortest to reduce iterations
	  var arrays = Array.prototype.slice.call(arguments).sort(function(a, b) {
	    return a.length - b.length;
	  });

	  // Use first array[0] as the base.
	  var a = arrays.shift();

	  var result = [];
	  for (var i = a.length; i--;) {

	    var val = a[i];

	    // Prevent duplicates
	    if (result.indexOf(val) < 0) {

	      // Seek
	      var found = true;
	      for (var ii = arrays.length; ii--;) {
	        if (arrays[ii].indexOf(val) < 0) {
	          found = false;
	          break;
	        }
	      }

	      if (found) {
	        result.push(val);
	      }

	    }

	  }

	  return result;

	}

	/*
	// Slower, but smaller code-base:
	function intersect (){
		
		// - Arguments -> traditional array,
		// - First item ( arrays[0] ) = shortest to reduce iterations
		var arrays = Array.prototype.slice.call(arguments).sort(function(a, b) {
	        return a.length - b.length;
	    });
		
		// Use first array[0] as the base.
		var a = arrays.shift();

		return a.filter(function (val, idx, aa) {
			
						// Seek
		                for(var i=arrays.length; i--;){
		                    if (arrays[i].indexOf(val) < 0) {
							    return false;
						    }
		                }
						
						// Prevent duplicates
		                return aa.indexOf(val) === idx;
		
					});

	}
	*/

	var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
	var arr2 = ['taco', 'fish', 'apple', 'pizza', 'apple', 'apple'];
	var arr3 = ['banana', 'pizza', 'fish', 'apple', 'fish'];

	var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
	var arr2 = ['taco', 'fish', 'apple', 'pizza', 'apple', 'apple'];
	var arr3 = ['banana', 'pizza', 'fish', 'apple', 'fish'];


	var result = intersect(arr1, arr2, arr3);

	 // For fiddle output:
	var elem = document.getElementById("result");
	elem.innerHTML = JSON.stringify(result);
	console.log(result);
<div id="result">Results</div>

사용가능array#reduce그리고.array#filter. 각 배열에 대해 모든 고유 값을 얻고,Map그들의 수를 조사하고 유지합니다.한 번 끝나면,array#filter배열 길이에 기반한 이 룩업.

const commonElements = (...arr) => {
  const lookup = arr.reduce((map, a) => {
    const unique = [...new Set(a)];
    unique.forEach(v => {
      map.set(v, (map.get(v) || 0) + 1)
    });
    return map;
  },new Map());
  return [...lookup.keys()].filter(k => lookup.get(k) === arr.length);
}

const arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'],
      arr2 = ['taco', 'fish', 'apple', 'pizza'],
      arr3 = ['banana', 'pizza', 'fish', 'apple'];
console.log(commonElements(arr1,arr2,arr3));

또 하나의 해결책:

const arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
const arr2 = ['taco', 'fish', 'apple', 'pizza'];
const arr3 = ['banana', 'pizza', 'fish', 'apple'];
const combinedArr = [arr1, arr2, arr3];

const result  = combinedArr
    .flatMap(([...values]) => values)
    .filter((value, index, coll) => (coll.indexOf(value) === index) && combinedArr.every(
        (values) => values.includes(value)
    ));
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

이 방법은 각 항목의 개수를 계산합니다.모든 배열을 반복한 후에는 배열 개수와 동일한 개수가 선택됩니다.

일반적으로 말하면, 함수는 배열 배열을 수용하고, 원시 값 대신 객체를 사용하는 경우에 지도 키를 생성하는 비교 함수입니다.

첫 번째 배열의 인스턴스를 참조로 사용하여 공통 값 배열을 반환합니다.

function commonValues<T>(arrays: T[][], keyFn: (item: T) => string): T[] {
  const counts: Record<any, { count: number, item: T }> = {}
  for (const array of arrays) {
    for (const item of array) {
      const key = keyFn(item)
      let entry = counts[key]
      if (!entry) {
        entry = {count: 0, item}
        counts[key] = entry
      }
      entry.count++
    }
  }
  return Object.values(counts)
      .filter(it => it.count === arrays.length)
      .map(it => it.item)
}

// 이 기본 예에서 키 함수는 단순히 문자열을 반환합니다.

var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2 = ['taco', 'fish', 'apple', 'pizza'];
var arr3 = ['banana', 'pizza', 'fish', 'apple'];

const common = commonItems([arr1,arr2,arr3], it=>it)

function commonValues(arrays, keyFn) {
  const counts = {}
  for (const array of arrays) {
    for (const item of array) {
      const key = keyFn(item)
      let entry = counts[key]
      if (!entry) {
        entry = {count: 0, item}
        counts[key] = entry
      }
      entry.count++
    }
  }
  return Object.values(counts)
      .filter(it => it.count === arrays.length)
      .map(it => it.item)
}

var arr1 = ['apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2 = ['taco', 'fish', 'apple', 'pizza'];
var arr3 = ['banana', 'pizza', 'fish', 'apple'];

const found = commonValues([arr1,arr2,arr3], it=>it)

console.log('common', found)

언급URL : https://stackoverflow.com/questions/11076067/finding-matches-between-multiple-javascript-arrays

반응형