How to calculate intersection of multiple arrays in JavaScript? And what does [equals: function] mean?

前端 未结 12 2128
广开言路
广开言路 2020-11-29 06:13

I am aware of this question, simplest code for array intersection but all the solutions presume the number of arrays is two, which cannot be certain in my case.

I ha

相关标签:
12条回答
  • 2020-11-29 06:19

    Using a combination of ideas from several contributors and the latest ES6 goodness, I arrived at

    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"]

    0 讨论(0)
  • 2020-11-29 06:19

    Intersection of a variable number of arrays.

    This is how I do it:

    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;
      }
    }
    

    SNIPPET

    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);

    0 讨论(0)
  • 2020-11-29 06:20

    I wrote a helper function for this:

    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;
    }
    

    Use it like this:

    intersection(array1, array2, array3, array4); //["Lorem"]
    

    Or like this:

    intersection([array1, array2, array3, array4]); //["Lorem"]
    

    Full code here

    UPDATE 1

    A slightly smaller implementation here using filter

    0 讨论(0)
  • 2020-11-29 06:23

    This can be done pretty succinctly if you fancy employing some recursion and the new ES2015 syntax:

    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));

    0 讨论(0)
  • 2020-11-29 06:26
    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));
    };
    
    0 讨论(0)
  • 2020-11-29 06:27

    For anyone confused by this in the future,

    _.intersection.apply(_, arrayOfArrays)
    

    Is in fact the most elegant way to do this. But:

    var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
    arrayOfArrays = _.intersection.apply(_, arrayOfArrays);
    

    Will not work! Must do

    var differentVariableName = _.intersection.apply(_,arrayOfArrays);
    
    0 讨论(0)
提交回复
热议问题