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



Je voudrais comprendre la meilleure façon de filtrer un tableau de tous les éléments d'un autre . J'ai essayé avec la fonction de filtre, mais il ne vient pas à moi comment lui donner les valeurs que je veux enlever.

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

si la fonction filter n'est pas utile, comment l'implémenter ?

Edit: j'ai vérifié la question dupliquée possible, et il pourrait être utile pour ceux qui comprennent javascript facilement. La réponse cochée comme bonne rend les choses faciles.

58
demandé sur Koop4 2016-01-20 16:38:31

14 réponses

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

var filtered = [1, 2, 3, 4].filter(
  function(e) {
    return this.indexOf(e) < 0;
  },
  [2, 4]
);
73
répondu Simon Hi 2018-06-03 21:03:59

je ferais comme suit;

var arr = [1,2,3,4],
    brr = [2,4],
    res = arr.filter(f => !brr.includes(f));
console.log(res);
41
répondu Redu 2016-12-15 16:33:14
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 callback, 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
});

Démo tableau d'objets

Démo diff tableau d'objets avec lodash

22
répondu AshBringer 2017-06-23 09:32:59

        /* 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);
4
répondu David Alan Condit 2018-07-30 16:16:35

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

vous devez 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 qu'elle ne soit assignée

1
répondu suvroc 2016-01-20 13:42:36

vous pouvez utiliser le filtre et puis pour la fonction de filtre utiliser une réduction du tableau de filtrage qui vérifie et renvoie true quand il trouve une correspondance puis inverser à la return (!). La fonction filter est appelée une fois par élément dans le tableau. Vous n'êtes pas à faire une comparaison de l'un quelconque des éléments dans la fonction dans votre post.

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
répondu Goblinlord 2016-01-20 14:07:55

un tableau filtrant plus flexible d'un autre tableau qui contient les propriétés de l'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
répondu syarul 2017-12-19 09:37:21

les exemples suivants utilisent new Set() pour créer un tableau filtré qui n'a que des éléments uniques:

tableau avec types de données primitives: 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 avec les objets comme les articles:

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
répondu didinko 2018-06-07 08:57:59

toutes les solutions ci-dessus" fonctionnent", mais sont moins qu'optimales pour la performance et sont tous l'approche du problème de la même manière qui est la recherche linéaire toutes les entrées à chaque point en utilisant tableau.prototype.index du tableau ou .prototype.comprend . Une solution beaucoup plus rapide (beaucoup plus rapide même qu'une recherche binaire pour la plupart des cas) serait de trier les tableaux et de sauter en avant que vous allez le long comme vu ci-dessous. Cependant, un inconvénient est que cela nécessite toutes les entrées dans le tableau des nombres ou des chaînes de caractères. Toutefois, la recherche binaire peut, dans certains rares cas, être plus rapide que la progressive recherche linéaire. Ces cas découlent du fait que ma recherche progressive linéaire a une complexité de O(2n 1 +n 2 ) (uniquement O (n 1 +n 2 ) dans la version C/C++ plus rapide) (où n 1 est le tableau recherché et n 2 est le tableau de filtre), alors que la recherche binaire a une complexité de O(N 1 ceil(log 2 n 2 )) (ceil = arrondir -- à la ceil ing), et, enfin, l'indexde recherche a une complexité très variable entre O(n 1 ) et O(n 1 n 2 ) , la moyenne O(n 1 ceil(n 2 ÷2)) . Ainsi, indexOf sera seulement le plus rapide, en moyenne, dans les cas de (n 1 , n 2 ) equaling {1,2} , {1,3} , ou {x, 1 / x, . Toutefois, il est toujours pas une représentation parfaite du matériel moderne. IndexOf est nativement optimisé dans la mesure la plus complète imaginable dans la plupart des navigateurs modernes, ce qui le rend très sujet aux lois de prédiction de branche . Ainsi, si nous faisons la même hypothèse sur indexOf comme nous le faisons avec la recherche progressive linéaire et binaire -- que le tableau est présenté -- alors, selon les statistiques énumérées dans le lien, Nous pouvons nous attendre à environ une vitesse de 6x pour IndexOf, en déplaçant sa complexité à entre O(n 1 ÷6) et O(n 1 n 2 ) , la moyenne O(n 1 ceil(n 2 7÷12)) . Enfin, notez que la solution ci-dessous ne fonctionnera jamais avec les objets car il est impossible d'obtenir le pointeur d'objet interne (pour comparaison numérique) en javascript.

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return a - b; }
var Math_clz32 = Math.clz32;
function filterArrayByAnotherArray(searchArray, filterArray, isInteger = false, i = 0) {
    if (isInteger) { // 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(function(currentValue) {
            var lo = -1, hi = filterArrayLen;
            while (1 + lo !== hi) {
                const mi = (hi + lo) >> 1;
                if (currentValue <= filterArray[mi]) hi = mi; else lo = mi;
            }
            return filterArray[hi] !== currentValue;
        });
    }
}

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

1
répondu Jack Giffin 2018-06-14 01:36:28

l'ao peut aussi être mis en œuvre dans ES6 comme suit

ES6:

 const filtered = [1, 2, 3, 4].filter(e => {
    return this.indexOf(e) < 0;
  },[2, 4]);
1
répondu Think-Twice 2018-09-06 04:10:50

vous pouvez configurer la fonction filter pour itérer sur le"filter array".

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
répondu metapod 2016-01-20 13:50:21

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
répondu hypemichael 2016-01-20 14:24:54

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
répondu hypemichael 2016-01-20 17:32:40

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

disons que vous avez votre tableau [1,2,3,4] que vous souhaitez filtrer() avec les indices spécifié dans la [2,4] tableau.

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
répondu lama 2018-02-21 15:07:46