jQuery-查找多个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);组合在一起,但这只是给我一个包含所有内容以及重复项的数组。 是否可以轻松完成此操作而无需诸如underscore.js之类的库的开销?

(太好了,现在我也饿了!)

编辑我想我应该提到的是,可能存在未知数量的数组,我只是以3为例。

CBarr asked 2020-01-13T16:15:14Z
9个解决方案
83 votes
var result = arrays.shift().filter(function(v) {
    return arrays.every(function(a) {
        return a.indexOf(v) !== -1;
    });
});

演示:[http://jsfiddle.net/nWjcp/2/]

您可以首先对外部Array进行排序,以在开始时获得最短的Array ...

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

6 revsuser1106925 answered 2020-01-13T16:15:39Z
13 votes

现在,您已经向问题中添加了不确定数量的数组,这是另一种方法,该方法将每个项目的计数收集到一个对象中,然后整理具有最大计数的项目。

这种方法的优点:

  1. 如果数组较大,则暴力破解搜索选项(由其他答案使用)的速度要快约15倍
  2. 不需要ES5或ES5填充程序(适用于所有浏览器)
  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的答案快10倍以上。


这是一个使用ES6 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>";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>";

jfriend00 answered 2020-01-13T16:16:53Z
11 votes

假设有一个数组,我们希望找到它们的交集,那么最简单的单衬板方法可能是

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

Redu answered 2020-01-13T16:17:17Z
3 votes

有两点想法-您只能比较最短数组中的项目,并防止在返回的数组中重复。

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

kennebec answered 2020-01-13T16:17:46Z
2 votes

假定数组为数组并检查所有数组:

演示:[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;
})
charlietfl answered 2020-01-13T16:18:10Z
2 votes

这里是单行解决方案。 您可以将其分为两个思考步骤:

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

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

dinigo answered 2020-01-13T16:18:48Z
1 votes

这适用于任意数量的数组:

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);
Blender answered 2020-01-13T16:19:09Z
0 votes

仅此而已,另一种漫长的方法:

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>'));
RobG answered 2020-01-13T16:19:37Z
0 votes

这实质上是所有答案的汇总:

<div id="result">Results</div>
<div id="result">Results</div>

bob answered 2020-01-13T16:21:04Z
translate from https://stackoverflow.com:/questions/11076067/finding-matches-between-multiple-javascript-arrays