[英]How to calculate intersection of multiple arrays in JavaScript? And what does [equals: function] mean?
我知道這個問題,最簡單的數組交集代碼,但所有解決方案都假定 arrays 的數量是兩個,在我的情況下不能確定。
我的頁面上有包含 arrays 數據的 div。 我想找到所有 arrays 共有的值。 我不知道我將提前擁有多少個 div/數組。 計算所有 arrays 共有值的最佳方法是什么?
var array1 = ["Lorem", "ipsum", "dolor"];
var array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
var array3 = ["Jumps", "Over", "Lazy", "Lorem"];
var array4 = [1337, 420, 666, "Lorem"];
//Result should be ["Lorem"];
我在其他地方找到了另一個解決方案,使用 Underscore.js。
var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
_.intersection.apply(_, arrayOfArrays)
//Result is [43]
我已經用簡單的虛擬數據對此進行了測試,它似乎有效。 但由於某種原因,我正在生產的一些 arrays 包含簡單的字符串,也自動包含一個附加值,“等於:函數”:
["Dummy1", "Dummy2", "Dummy3", equals: function]
每當我使用 Underscore.js 交集方法時,在 arrays 數組上,我總是在開發工具中得到 [equals: function],而不是 - 如果“Dummy3”對所有 arrays - [“Dummy3”] 是通用的。
所以 TL;DR 是否有另一種適合我的情況的數組交集解決方案? 任何人都可以解釋 [equals: function] 在這里的含義嗎? 當我在開發工具中展開項目時,它會生成一個空數組和 arrays 上可用的方法列表(pop、push、shift 等),但這些方法都淡出,而等於:function 突出顯示。
您可以將Array#reduce
與Array#filter
和Array#includes
。
var array1 = ["Lorem", "ipsum", "dolor"], array2 = ["Lorem", "ipsum", "quick", "brown", "foo"], array3 = ["Jumps", "Over", "Lazy", "Lorem"], array4 = [1337, 420, 666, "Lorem"], data = [array1, array2, array3, array4], result = data.reduce((a, b) => a.filter(c => b.includes(c))); console.log(result);
我為此編寫了一個輔助函數:
function intersection() {
var result = [];
var lists;
if(arguments.length === 1) {
lists = arguments[0];
} else {
lists = arguments;
}
for(var i = 0; i < lists.length; i++) {
var currentList = lists[i];
for(var y = 0; y < currentList.length; y++) {
var currentValue = currentList[y];
if(result.indexOf(currentValue) === -1) {
var existsInAll = true;
for(var x = 0; x < lists.length; x++) {
if(lists[x].indexOf(currentValue) === -1) {
existsInAll = false;
break;
}
}
if(existsInAll) {
result.push(currentValue);
}
}
}
}
return result;
}
像這樣使用它:
intersection(array1, array2, array3, array4); //["Lorem"]
或者像這樣:
intersection([array1, array2, array3, array4]); //["Lorem"]
完整代碼在這里
更新 1
這里使用filter
稍微小一點的實現
如果您喜歡使用一些遞歸和新的 ES2015 語法,這可以非常簡潔地完成:
const array1 = ["Lorem", "ipsum", "dolor"]; const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"]; const array3 = ["Jumps", "Over", "Lazy", "Lorem"]; const array4 = [1337, 420, 666, "Lorem"]; const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]]; // Filter xs where, for a given x, there exists some y in ys where y === x. const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x)); // When there is only one array left, return it (the termination condition // of the recursion). Otherwise first find the intersection of the first // two arrays (intersect2), then repeat the whole process for that result // combined with the remaining arrays (intersect). Thus the number of arrays // passed as arguments to intersect is reduced by one each time, until // there is only one array remaining. const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest); console.log(intersect(array1, array2, array3, array4)); console.log(intersect(...arrayOfArrays)); // Alternatively, in old money, var intersect2ES5 = function (xs, ys) { return xs.filter(function (x) { return ys.some(function (y) { return y === x; }); }); }; // Changed slightly from above, to take a single array of arrays, // which matches the underscore.js approach in the Q., and is better anyhow. var intersectES5 = function (zss) { var xs = zss[0]; var ys = zss[1]; var rest = zss.slice(2); if (ys === undefined) { return xs; } return intersectES5([intersect2ES5(xs, ys)].concat(rest)); }; console.log(intersectES5([array1, array2, array3, array4])); console.log(intersectES5(arrayOfArrays));
結合幾個貢獻者的想法和最新的 ES6 優點,我得到了
const array1 = ["Lorem", "ipsum", "dolor"]; const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"]; const array3 = ["Jumps", "Over", "Lazy", "Lorem"]; const array4 = [1337, 420, 666, "Lorem"]; Array.prototype.intersect = function intersect(a, ...b) { const c = function (a, b) { b = new Set(b); return a.filter((a) => b.has(a)); }; return undefined === a ? this : intersect.call(c(this, a), ...b); }; console.log(array1.intersect(array2, array3, array4)); // ["Lorem"]
對於未來對此感到困惑的任何人,
_.intersection.apply(_, arrayOfArrays)
實際上是最優雅的方式來做到這一點。 但:
var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
arrayOfArrays = _.intersection.apply(_, arrayOfArrays);
不管用! 必須做
var differentVariableName = _.intersection.apply(_,arrayOfArrays);
不依賴於 es6 或任何庫的小型遞歸分治解決方案。
它接受一個數組數組,這使得代碼更短,並允許您使用 map 傳遞參數。
function intersection(a) { if (a.length > 2) return intersection([intersection(a.slice(0, a.length / 2)), intersection(a.slice(a.length / 2))]); if (a.length == 1) return a[0]; return a[0].filter(function(item) { return a[1].indexOf(item) !== -1; }); } var list1 = [ 'a', 'b', 'c' ]; var list2 = [ 'd', 'b', 'e' ]; var list3 = [ 'f', 'b', 'e' ]; console.log(intersection([list1, list2, list3]));
如果您可以使用 ES6 Maps 並且您的數組項是標量值(很容易用作 Map 鍵),那么您可以嘗試這個(在我的情況下有效):
const intersect_lists = (lists) => {
const results = []
const lookup = new Map()
lists.map((list, idx) => {
list.map((element) => {
const count = lookup.get(element) || 0
if(count === idx) {
lookup.set(element, 1 + count)
} else {
lookup.delete(element)
}
})
})
// only elements present in all lists will have
// their respective counter equllling the total number of lists
Array.from(lookup.keys()).map((key) => {
if(lookup.get(key) === lists.length) {
results.push(key)
}
})
return results
}
或者,您可以通過增加長度來對“列表”(列表)進行預排序,以避免外部 map() 調用的大量迭代,特別是如果列表長度是異類的:
lists.sort((l1, l2) => l1.length - l2.length).map((list, idx) => { ... })
您使用 _lodash 的代碼運行良好。
正如你在這個小提琴中所說的那樣:
這段代碼:
var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
var a = _.intersection.apply(_, arrayOfArrays);
console.log(a);
console.log(a.length);
將有輸出:
[42]
1
也許你看到
等於:函數
因為您正在使用某種調試器。
嘗試只用console.log
打印數組,你只會得到 42。
洛達什純:
_.keys(_.pickBy(_.groupBy(_.flatten(arrays)), function (e) {return e.length > 1}))
帶有普通 js 的 Lodash:
var elements = {}, duplicates = {};
_.each(arrays, function (array) {
_.each(array, function (element) {
if (!elements[element]) {
elements[element] = true;
} else {
duplicates[element] = true;
}
});
});
_.keys(duplicates);
Arg0n 的答案很好,但以防萬一有人在尋找對象數組的交集,我稍微修改了 Arg0n 的答案以解決它。
function getIntersectedData() {
var lists = [[{a:1,b:2},{a:2,b:2}],[{a:1,b:2},{a:3,b:3}],[{a:1,b:2},{a:4,b:4}]];
var result = [];
for (var i = 0; i < lists.length; i++) {
var currentList = lists[i];
for (var y = 0; y < currentList.length; y++) {
var currentValue = currentList[y];
if (customIndexOf(result,currentValue)) {
var existsInAll = true;
for (var x = 0; x < lists.length; x++) {
if(customIndexOf(lists[x],currentValue)){
existsInAll = false;
break;
}
}
if (existsInAll) {
result.push(currentValue);
}
}
}
return result;
}
}
function customIndexOf(array,value){
var notFind = true;
array.forEach(function(element){
if(element.a === value.a){
notFind = false;
}
});
return notFind;
}
我設法通過reduce
調用來完成此操作:
var intersected = intersect([[1, 2, 3], [2, 3, 4], [3, 4, 5]]); console.log(intersected); // [3] function intersect(arrays) { if (0 === arrays.length) { return []; } return arrays.reduce((intersection, array) => { return intersection.filter(intersectedItem => array.some(item => intersectedItem === item)); }, arrays[0]); }
可變數量數組的交集。
這就是我的做法:
function getArraysIntersection(list1, list2, ...otherLists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (otherLists.length) {
return getArraysIntersection(result, otherLists.shift(), ...otherLists);
}
else {
return result;
}
}
片段
function getArraysIntersection(list1, list2, ...otherLists) { const result = []; for (let i = 0; i < list1.length; i++) { let item1 = list1[i]; let found = false; for (var j = 0; j < list2.length && !found; j++) { found = item1 === list2[j]; } if (found === true) { result.push(item1); } } if (otherLists.length) { return getArraysIntersection(result, otherLists.shift(), ...otherLists); } else { return result; } } const a = {label: "a", value: "value_A"}; const b = {label: "b", value: "value_B"}; const c = {label: "c", value: "value_C"}; const d = {label: "d", value: "value_D"}; const e = {label: "e", value: "value_E"}; const arr1 = [a,b,c]; const arr2 = [a,b,c]; const arr3 = [c]; const t0 = performance.now(); const intersection = getArraysIntersection(arr1,arr2,arr3); const t1 = performance.now(); console.log('This took t1-t0: ' + (t1-t0).toFixed(2) + ' ms'); console.log(intersection);
const intersect = (arrayA, arrayB) => {
return arrayA.filter(elem => arrayB.includes(elem));
};
const intersectAll = (...arrays) => {
if (!Array.isArray(arrays) || arrays.length === 0) return [];
if (arrays.length === 1) return arrays[0];
return intersectAll(intersect(arrays[0], arrays[1]), ...arrays.slice(2));
};
我發現的最干凈的方法實際上沒有列在這個頁面上,所以你在這里:
arrays[0].filter(elem => arrays.every(array => array.includes(elem)))
讀起來像漂亮、清晰的英語:每個數組都包含元素。 不過,它假設您在數組中至少有 1 個元素。 如果你不能做出這個假設,你可以使用可選鏈接:
arrays?[0].filter(elem => arrays.every(array => array.includes(elem))) ?? []
對於可能需要的任何人,這實現了數組數組內的交集:
intersection(array) {
if (array.length === 1)
return array[0];
else {
array[1] = array[0].filter(value => array[1].includes(value));
array.shift();
return intersection(array);
}
}
function getIntersection(ar1,ar2,...arrays){
if(!ar2) return ar1
let intersection = ar1.filter(value => ar2.includes(value));
if(arrays.length ===0 ) return intersection
return getIntersection(intersection,...arrays)
}
console.log(getIntersection([1,2,3], [3,4], [5,6,3]) // [3]
溶膠與地圖
// nums1 = [1,2,2,1], nums2 = [2,2]
// n m
// O(nm) + space O(min(n, m))
// preprocess nums2 to a Map<number, count>
// O(n + m) + space(min(n, m))
// process the shorter one
let preprocessTarget = nums1
let loopTarget = nums2
if (nums1.length > nums2.length) {
preprocessTarget = nums2
loopTarget = nums1
}
// Map<element, number>
const countMap = new Map()
for (let num of preprocessTarget) {
if (countMap.has(num)) {
countMap.set(num, countMap.get(num) + 1)
} else {
countMap.set(num, 1)
}
}
const result = []
for (let num of loopTarget) {
if (countMap.has(num)) {
result.push(num)
const count = countMap.get(num)
if (count === 1) {
countMap.delete(num)
} else {
countMap.set(num, count - 1)
}
}
}
return result
Function 計算 JavaScript 中多個 arrays 的交集編寫一個創建唯一值數組的方法,該數組包含在所有給定的 arrays 中預期結果:([1, 2], [2, 3]) => [2]
const arr1 = [1, 2, 1, 2, 1, 2]; const arr2 = [2, 3]; const arr3 = ["a", "b"]; const arr4 = ["b", "c"]; const arr5 = ["b", "e", "c"]; const arr6 = ["b", "b", "e"]; const arr7 = ["b", "c", "e"]; const arr8 = ["b", "e", "c"]; const intersection = (...arrays) => { (data = [...arrays]), (result = data.reduce((a, b) => a.filter((c) => b.includes(c)))); return [...new Set(result)]; }; console.log(intersection(arr1, arr2)); // [2] console.log(intersection(arr3, arr4, arr5)); // ['b'] console.log(intersection(arr5, arr6, arr7, arr8)); // ['b', 'e']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.