여러 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>");
질문에 불특정 수의 배열을 추가했으므로 각 항목에 대한 카운트를 개체로 수집한 다음 최대 카운트를 가지는 항목을 수집하는 다른 방법이 있습니다.
이 접근 방식의 장점:
- 어레이 크기가 더 큰 경우 검색 옵션(다른 답변에서 사용)보다 최대 15배 빠름
- ES5 또는 ES5 shim 필요 없음(모든 브라우저에서 작동)
- 완전 비파괴(소스 데이터를 전혀 변경하지 않음)
- 소스 배열에서 중복 항목을 처리
- 임의 수의 입력 배열을 처리합니다.
여기 암호가 있습니다.
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;
})
여기 한 줄 솔루션이 있습니다.두 가지 생각 단계로 나눌 수 있습니다.
- 두 배열 간 결합/교차 계산
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}`);
- 내용 축소: 누적 교차점과 다음 배열 사이의 교차점을 계산합니다.
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
'programing' 카테고리의 다른 글
jQuery로 RSS 구문 분석 (0) | 2023.11.06 |
---|---|
ngModel의 *는 무엇입니까?달러 valid기 파이프라인? (0) | 2023.11.06 |
app.yaml로 환경변수를 GAE에 안전하게 저장 (0) | 2023.11.06 |
Oracle의 다른 사용자에게 저장 프로시저에 대한 권한 부여 (0) | 2023.11.06 |
부유한 디브를 부모의 100% 높이로 만드는 방법은? (0) | 2023.11.06 |