web-dev-qa-db-fra.com

Comment filtrer un tableau de tous les éléments d'un autre tableau


Je voudrais comprendre le meilleur moyen de filtrer un tableau de tous les éléments d’un autre . J'ai essayé avec la fonction de filtrage, mais elle ne me dit pas comment lui donner les valeurs que je veux supprimer. 
Quelque chose comme:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallback);
// filteredArray should now be [1,3]


function myCallBack(){
    return element ! filteredArray; 
    //which clearly can't work since we don't have the reference <,< 
}

au cas où la fonction de filtrage ne serait pas utile, comment la mettriez-vous en œuvre?
Edit: J'ai vérifié la question possible en double, et cela pourrait être utile pour ceux qui comprennent le javascript facilement. La réponse vérifiée comme bonne facilite les choses.

73
Koop4

Vous pouvez utiliser le paramètre this de la fonction filter() pour éviter de stocker votre tableau de filtres dans une variable globale.

var filtered = [1, 2, 3, 4].filter(
    function(e) {
      return this.indexOf(e) < 0;
    },
    [2, 4]
);
console.log(filtered);

89
Simon Hi

Je ferais comme suit;

var arr = [1,2,3,4],
    brr = [2,4],
    res = arr.filter(f => !brr.includes(f));
console.log(res);

63
Redu
var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallBack);

function myCallBack(el){
  return anotherOne.indexOf(el) < 0;
}

Dans le rappel, vous vérifiez si chaque valeur de array est dans anotherOne

https://jsfiddle.net/0tsyc1sx/

Si vous utilisez lodash.js, utilisez _.difference 

filteredArray = _.difference(array, anotherOne);

Démo

Si vous avez un tableau d'objets:

var array = [{id :1, name :"test1"},{id :2, name :"test2"},{id :3, name :"test3"},{id :4, name :"test4"}];

var anotherOne = [{id :2, name :"test2"}, {id :4, name :"test4"}];

var filteredArray  = array.filter(function(array_el){
   return anotherOne.filter(function(anotherOne_el){
      return anotherOne_el.id == array_el.id;
   }).length == 0
});

Tableau de démonstration d'objets

Tableau de démonstration des objets avec lodash

25
AshBringer

        /* Here's an example that uses (some) ES6 Javascript semantics to filter an object array by another object array. */

        // x = full dataset
        // y = filter dataset
        let x = [
            {"val": 1, "text": "a"},
            {"val": 2, "text": "b"},
            {"val": 3, "text": "c"},
            {"val": 4, "text": "d"},
            {"val": 5, "text": "e"}
            ],
            y = [
            {"val": 1, "text": "a"},
            {"val": 4, "text": "d"}               
            ];

        // Use map to get a simple array of "val" values. Ex: [1,4]
        let yFilter = y.map(itemY => { return itemY.val; });

        // Use filter and "not" includes to filter the full dataset by the filter dataset's val.
        let filteredX = x.filter(itemX => !yFilter.includes(itemX.val));

        // Print the result.
        console.log(filteredX);

7
David Alan Condit

Toutes les solutions ci-dessus "fonctionnent", mais ne sont pas optimales en termes de performances et abordent le problème de la même manière, qui consiste à rechercher toutes les entrées de manière linéaire à chaque point à l'aide de Array.prototype.indexOf ou Array.prototype. .includes . Une solution beaucoup plus rapide (bien plus rapide que la recherche binaire dans la plupart des cas) serait de trier les tableaux et de passer au suivant, comme vous le verrez ci-dessous. Cependant, un inconvénient est que cela nécessite que toutes les entrées du tableau soient des nombres ou des chaînes. Cependant, la recherche binaire peut aussi dans certains cas être plus rapide que la recherche linéaire progressive. Ces cas résultent du fait que ma recherche linéaire progressive a une complexité de O (2n1+ n2) (seulement O (n1+ n2) dans la version plus rapide en C/C++) (où n1 est le tableau recherché et n2 est le tableau de filtres), alors que la recherche binaire a une complexité de O (n1ceil (log2n2)) (ceil = arrondi au ceil ing), et enfin, la recherche indexOf a une complexité très variable entre O (n1) et O (n1n2), faisant la moyenne sur O (n1ceil (n2÷ 2)). Ainsi, indexOf ne sera en moyenne le plus rapide que dans le cas de (n1, n2) égal à {1,2}, {1,3} ou {x, 1 | x∈N}. Cependant, ce n'est toujours pas une représentation parfaite du matériel moderne. IndexOf est optimisé en natif dans toute la mesure possible dans la plupart des navigateurs modernes, ce qui le rend très soumis aux lois de prédiction de branche . Ainsi, si nous faisons la même hypothèse sur indexOf que pour la recherche linéaire et binaire progressive - que le tableau est trié -, alors, selon les statistiques répertoriées dans le lien, nous pouvons nous attendre à une vitesse environ 6x plus rapide pour IndexOf, déplaçant sa complexité entre O (n16) et O (n1n2), faisant la moyenne sur O (n1ceil (n27 12)). Enfin, notez que la solution ci-dessous ne fonctionnera jamais avec des objets car il est impossible d’obtenir le pointeur d’objet interne (pour une comparaison numérique) en javascript.

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }

const Math_clz32 = Math.clz32 || (function(log, LN2){
  return function(x) {
    return 31 - log(x >>> 0) / LN2 | 0; // the "| 0" acts like math.floor
  };
})(Math.log, Math.LN2);

function filterArrayByAnotherArray(searchArray, filterArray, i = 0) {
    if (
        // NOTE: This does not check the whole array. But, if you know
        //        that there are only strings or numbers (not a mix of
        //        both) in the array, then this is a safe assumption.
        // Always use `==` with `typeof` because browsers can optimize
        //  the `==` into `===` (ONLY IN THIS CIRCUMSTANCE)
        typeof searchArray[0] == "number" &&
        typeof filterArray[0] == "number" &&
        (searchArray[0]|0) === searchArray[0] &&
        (filterArray[0]|0) === filterArray[0]
    ) {filterArray
        // if all entries in both arrays are integers
        searchArray.sort(sortIntArray);
        filterArray.sort(sortIntArray);
    } else {
        searchArray.sort(sortAnyArray);
        filterArray.sort(sortAnyArray);
    }
    var searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
    var progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
    var binarySearchComplexity= (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;
    // After computing the complexity, we can predict which algorithm will be the fastest
    if (progressiveLinearComplexity < binarySearchComplexity) {
        // Progressive Linear Search
        return searchArray.filter(function(currentValue){
            while (filterArray[i] < currentValue) ++i;
            // +undefined = NaN, which is always false for <, avoiding an infinite loop
            return filterArray[i] !== currentValue;
        });
    } else {
        // Binary Search
        return searchArray.filter(
            fastestBinarySearch(filterArray)
        );
    }
}

// see https://stackoverflow.com/a/44981570/5601591 for implementation
//  details about this binary search algorithim

function fastestBinarySearch(array){
  var initLen = (array.length|0) - 1 |0;

  const compGoto = Math_clz32(initLen) & 31;
  return function(ARG_sValue) {
    var sValue = ARG_sValue |0;
    var len = initLen |0;
    switch (compGoto) {
      case 0:
        if (len & 0x80000000) {
          const nCB = len & 0x80000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 1:
        if (len & 0x40000000) {
          const nCB = len & 0xc0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 2:
        if (len & 0x20000000) {
          const nCB = len & 0xe0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 3:
        if (len & 0x10000000) {
          const nCB = len & 0xf0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 4:
        if (len & 0x8000000) {
          const nCB = len & 0xf8000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 5:
        if (len & 0x4000000) {
          const nCB = len & 0xfc000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 6:
        if (len & 0x2000000) {
          const nCB = len & 0xfe000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 7:
        if (len & 0x1000000) {
          const nCB = len & 0xff000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 8:
        if (len & 0x800000) {
          const nCB = len & 0xff800000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 9:
        if (len & 0x400000) {
          const nCB = len & 0xffc00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 10:
        if (len & 0x200000) {
          const nCB = len & 0xffe00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 11:
        if (len & 0x100000) {
          const nCB = len & 0xfff00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 12:
        if (len & 0x80000) {
          const nCB = len & 0xfff80000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 13:
        if (len & 0x40000) {
          const nCB = len & 0xfffc0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 14:
        if (len & 0x20000) {
          const nCB = len & 0xfffe0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 15:
        if (len & 0x10000) {
          const nCB = len & 0xffff0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 16:
        if (len & 0x8000) {
          const nCB = len & 0xffff8000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 17:
        if (len & 0x4000) {
          const nCB = len & 0xffffc000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 18:
        if (len & 0x2000) {
          const nCB = len & 0xffffe000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 19:
        if (len & 0x1000) {
          const nCB = len & 0xfffff000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 20:
        if (len & 0x800) {
          const nCB = len & 0xfffff800;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 21:
        if (len & 0x400) {
          const nCB = len & 0xfffffc00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 22:
        if (len & 0x200) {
          const nCB = len & 0xfffffe00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 23:
        if (len & 0x100) {
          const nCB = len & 0xffffff00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 24:
        if (len & 0x80) {
          const nCB = len & 0xffffff80;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 25:
        if (len & 0x40) {
          const nCB = len & 0xffffffc0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 26:
        if (len & 0x20) {
          const nCB = len & 0xffffffe0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 27:
        if (len & 0x10) {
          const nCB = len & 0xfffffff0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 28:
        if (len & 0x8) {
          const nCB = len & 0xfffffff8;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 29:
        if (len & 0x4) {
          const nCB = len & 0xfffffffc;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 30:
        if (len & 0x2) {
          const nCB = len & 0xfffffffe;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 31:
        if (len & 0x1) {
          const nCB = len & 0xffffffff;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
    }
    // MODIFICATION: Instead of returning the index, this binary search
    //                instead returns whether something was found or not.
    if (array[len|0] !== sValue) {
       return true; // preserve the value at this index
    } else {
       return false; // eliminate the value at this index
    }
  };
}

Pour prouver la différence de vitesse, examinons quelques JSPerfs. Pour filtrant un tableau de 16 éléments , la recherche binaire est environ 17% plus rapide que indexOf, tandis que filterArrayByAnotherArray est environ 93% plus rapide que indexOf. Pour filtrant un tableau de 256 éléments , la recherche binaire est environ 291% plus rapide que indexOf, tandis que filterArrayByAnotherArray est environ 353% plus rapide que indexOf. Pour filtrer un tableau de 4096 éléments , la recherche binaire est environ 2655% plus rapide que indexOf, tandis que filterArrayByAnotherArray est environ 4627% plus rapide que indexOf.

3
Jack Giffin

Il y a plusieurs réponses à votre question, mais je ne vois personne utiliser lambda expression:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(x => anotherOne.indexOf(x) < 0);
2
Mati Cassanelli

L’OA peut également être implémenté dans ES6 comme suit

ES6:

 const filtered = [1, 2, 3, 4].filter(e => {
    return this.indexOf(e) < 0;
  },[2, 4]);
1
Hemadri Dasari

Un tableau de filtrage plus souple d'un autre tableau contenant des propriétés d'objet

function filterFn(array, diffArray, prop, propDiff) {
    diffArray = !propDiff ? diffArray : diffArray.map(d => d[propDiff])
    this.fn = f => diffArray.indexOf(f) === -1
    if (prop) {
         return array.map(r => r[prop]).filter(this.fn)
    } else {
         return array.filter(this.fn)
    }
}

//You can use it like this;

var arr = [];

for (var i = 0; i < 10; i++) {
    var obj = {}
    obj.index = i
    obj.value = Math.pow(2, i)
    arr.Push(obj)
}

var arr2 = [1, 2, 3, 4, 5]

var sec = [{t:2}, {t:99}, {t:256}, {t:4096}]

var log = console.log.bind(console)

var filtered = filterFn(arr, sec, 'value', 't')

var filtered2 = filterFn(arr2, sec, null, 't')

log(filtered, filtered2)

1
syarul

Les exemples suivants utilisent new Set() pour créer un tableau filtré comportant uniquement des éléments uniques:

Tableau contenant des types de données primitifs: chaîne, nombre, booléen, null, non défini, symbole:

const a = [1, 2, 3, 4];
const b = [3, 4, 5];
const c = Array.from(new Set(a.concat(b)));

Tableau contenant des objets en tant qu'objets:

const a = [{id:1}, {id: 2}, {id: 3}, {id: 4}];
const b = [{id: 3}, {id: 4}, {id: 5}];
const stringifyObject = o => JSON.stringify(o);
const parseString = s => JSON.parse(s);
const c = Array.from(new Set(a.concat(b).map(stringifyObject)), parseString);
1
didinko

La meilleure description de la fonction filter est https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/filter

Vous devriez simplement conditionner la fonction:

function conditionFun(element, index, array) {
   return element >= 10;
}
filtered = [12, 5, 8, 130, 44].filter(conditionFun);

Et vous ne pouvez pas accéder à la valeur de la variable avant son affectation

1
suvroc

Vous pouvez utiliser le filtre puis, pour la fonction de filtrage, utiliser une réduction du tableau de filtrage qui vérifie et renvoie la valeur true quand elle trouve une correspondance, puis l'inverse au retour (!). La fonction de filtrage est appelée une fois par élément dans le tableau. Vous ne comparez aucun des éléments de la fonction dans votre message.

var a1 = [1, 2, 3, 4],
  a2 = [2, 3];

var filtered = a1.filter(function(x) {
  return !a2.reduce(function(y, z) {
    return x == y || x == z || y == true;
  })
});

document.write(filtered);

1
Goblinlord

function arr(arr1,arr2){
  
  function filt(value){
    return arr2.indexOf(value) === -1;
    }
  
  return arr1.filter(filt)
  }

document.getElementById("p").innerHTML = arr([1,2,3,4],[2,4])
<p id="p"></p>

0
hypemichael

Vous pouvez configurer la fonction de filtrage pour parcourir le "tableau de filtres".

var arr = [1, 2, 3 ,4 ,5, 6, 7];
var filter = [4, 5, 6];

var filtered = arr.filter(
  function(val) {
    for (var i = 0; i < filter.length; i++) {
      if (val == filter[i]) {
        return false;
      }
    }
    return true;
  }
); 
0
metapod

var arr1= [1,2,3,4];
var arr2=[2,4]

function fil(value){
return value !=arr2[0] &&  value != arr2[1]
}

document.getElementById("p").innerHTML= arr1.filter(fil)
<!DOCTYPE html> 
<html> 
<head> 
</head>
<body>
<p id="p"></p>

0
hypemichael

Vous pouvez écrire une fonction filterByIndex () générique et utiliser l'inférence de type dans TS pour économiser les tracas avec la fonction de rappel:

supposons que vous ayez votre tableau [1,2,3,4] que vous voulez filtrer () avec les indices spécifiés dans le tableau [2,4].

var filtered = [1,2,3,4,].filter(byIndex(element => element, [2,4]))

la fonction byIndex attend la fonction element et un tableau et ressemble à ceci:

byIndex = (getter: (e:number) => number, arr: number[]) => (x: number) => {
    var i = getter(x);
    return arr.indexOf(i); 
}

le résultat est alors 

filtered = [1,3]
0
lama