簡體   English   中英

如何計算 JavaScript 中多個 arrays 的交集? [equals: function] 是什么意思?

[英]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#reduceArray#filterArray#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM