J'ai plusieurs tableaux avec des valeurs de chaîne et je veux les comparer et ne garder que les résultats de correspondance qui sont identiques entreTOUSd'entre eux.
Étant donné cet exemple de code:
var arr1 = ['Apple', 'orange', 'banana', 'pear', 'fish', 'pancake', 'taco', 'pizza'];
var arr2 = ['taco', 'fish', 'Apple', 'pizza'];
var arr3 = ['banana', 'pizza', 'fish', 'Apple'];
Je voudrais produire le tableau suivant qui contient les correspondances de tous les tableaux donnés:
['Apple', 'fish', 'pizza']
Je sais que je peux combiner tous les tableaux avec var newArr = arr1.concat(arr2, arr3);
mais cela me donne juste un tableau avec tout, plus les doublons. Cela peut-il être fait facilement sans avoir besoin des frais généraux des bibliothèques telles que underscore.js?
(Génial et maintenant j'ai faim aussi!)
EDITJe suppose que je devrais mentionner qu’il pourrait y avoir un nombre inconnu de tableaux, j’utilisais simplement 3 comme exemple.
var result = arrays.shift().filter(function(v) {
return arrays.every(function(a) {
return a.indexOf(v) !== -1;
});
});
DEMO:http://jsfiddle.net/nWjcp/2/
Vous pouvez d'abord trier le tableau extérieur pour obtenir le tableau le plus court au début ...
arrays.sort(function(a, b) {
return a.length - b.length;
});
Pour être complet, voici une solution qui traite les doublons dans les tableaux. Il utilise .reduce()
au lieu de .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;
}, []);
Maintenant que vous avez ajouté un nombre indéterminé de tableaux à la question, voici une autre approche qui collecte le nombre de chaque élément dans un objet, puis associe les éléments dont le nombre est maximal.
Avantages de cette approche:
Et voici le code:
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);
}
Démo de travail: http://jsfiddle.net/jfriend00/52mAP/
Pour votre information, cela ne nécessite pas ES5 et fonctionnera donc dans tous les navigateurs sans cale.
Lors d'un test de performances effectué sur 15 baies de disques de 1 000 fois chacune, il était plus de 10 fois plus rapide que la méthode de recherche utilisée dans la réponse de am not am am: http://jsperf.com/in-all-arrays .
Voici une version qui utilise une ES6 Map
et Set
pour dédoubler et garder une trace des comptes. Cela présente l'avantage que le type de données est préservé et peut être n'importe quoi (il n'est même pas nécessaire d'avoir une conversion de chaîne naturelle, les données peuvent même être des objets bien que les objets soient comparés pour être exactement le même objet, n'ayant pas le même propriétés/valeurs).
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>";
En supposant qu'il y ait un tableau de tableaux ceux dont nous voulons trouver l'intersection, une approche simple plus simple pourrait être
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>");
Quelques réflexions - vous pouvez comparer uniquement les éléments du tableau le plus court,
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();
valeur renvoyée: Apple,fish,pizza
DEMO - http://jsfiddle.net/kMcud/
Voici une solution à une seule ligne. Vous pouvez le scinder en deux étapes de réflexion:
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}`);
En supposant un tableau de tableaux et en vérifiant tous les tableaux:
DEMO: 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;
})
Cela devrait fonctionner pour n'importe quel nombre de tableaux:
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);
Ceci est essentiellement une compilation de toutes les réponses résumées:
// 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>
Juste pour le plaisir, une autre approche à main longue:
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']
];
Fonction pour ne jamais trouver de propriétés énumérables basées sur thise sur 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>'));