it-swarm.com.de

Filtern eines Arrays aus allen Elementen eines anderen Arrays


Ich würde gerne wissen, wie ein Array aus allen Elementen eines anderen gefiltert wird. Ich habe es mit der Filterfunktion versucht, aber es kommt nicht auf mich an, wie ich ihm die Werte geben möchte, die ich entfernen möchte. 
So etwas wie:

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

falls die Filterfunktion nicht nützlich ist, wie würden Sie dies implementieren?
Edit: Ich habe die mögliche doppelte Frage geprüft, und es könnte für diejenigen nützlich sein, die Javascript leicht verstehen. Die als gut überprüfte Antwort macht die Sache einfach.

73
Koop4

Sie können den Parameter this der Funktion filter() verwenden, um zu vermeiden, dass Ihr Filterarray in einer globalen Variablen gespeichert wird.

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

89
Simon Hi

Ich würde wie folgt vorgehen;

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

Im Callback prüfen Sie, ob sich jeder Wert von array in anotherOne befindet.

https://jsfiddle.net/0tsyc1sx/

Wenn Sie lodash.js verwenden, verwenden Sie _.difference

filteredArray = _.difference(array, anotherOne);

Demo

Wenn Sie ein Array von Objekten haben:

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

Demo Array von Objekten

Demo diff Array von Objekten mit 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

Alle oben genannten Lösungen "funktionieren", sind jedoch nicht optimal für die Leistung und gehen alle auf die gleiche Weise an das Problem heran, indem alle Einträge an jedem Punkt mit Array.prototype.indexOf oder - linear durchsucht werden. Array.prototype.includes . Eine weitaus schnellere Lösung (in den meisten Fällen sogar weitaus schneller als eine binäre Suche) wäre, die Arrays zu sortieren und wie unten dargestellt fortzufahren. Ein Nachteil ist jedoch, dass alle Einträge im Array Zahlen oder Zeichenfolgen sein müssen. In einigen seltenen Fällen ist die binäre Suche jedoch schneller als die progressive lineare Suche. Diese Fälle ergeben sich aus der Tatsache, dass meine progressive lineare Suche eine Komplexität von O (2n hat1+ n2) (nur O (n1+ n2) in der schnelleren C/C++ - Version) (wobei n1 ist das gesuchte Array und n2 ist das Filterarray), während die binäre Suche eine Komplexität von O (n1ceil (log2n2)) (ceil = aufrunden - auf ceil und schließlich hat die indexOf-Suche eine sehr variable Komplexität zwischen O (n1) und O (n1n2) , gemittelt auf O (n1ceil (n2÷ 2)) . Somit ist indexOf im Durchschnitt nur in den Fällen von (n1n2) entspricht {1,2} , {1,3} oder {x, 1 | x∈N} . Dies ist jedoch immer noch keine perfekte Darstellung moderner Hardware. IndexOf ist von Haus aus so weit optimiert, wie es in den meisten modernen Browsern vorstellbar ist, und unterliegt daher den Gesetzen von Verzweigungsvorhersage . Wenn wir also bei indexOf die gleiche Annahme treffen wie bei der progressiven linearen und binären Suche - dass das Array vorsortiert ist -, können wir gemäß den im Link aufgelisteten Statistiken für IndexOf eine etwa 6-fache Geschwindigkeit erwarten. Verschiebung seiner Komplexität zwischen O (n1÷ 6) und O (n1n2) , gemittelt auf O (n1ceil (n27 ÷ 12)) . Beachten Sie schließlich, dass die folgende Lösung niemals mit Objekten funktioniert, da es unmöglich ist, den internen Objektzeiger (für den numerischen Vergleich) in Javascript abzurufen. Wenn nur Javascript sein könnte

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) {
    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
    var i = 0;
    if (progressiveLinearComplexity < binarySearchComplexity) {
        // Progressive Linear Search
        return searchArray.filter(function(currentValue){
            while (filterArray[i] < currentValue) i=i+1|0;
            // +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
    }
  };
}

Weitere Informationen zum verwendeten binären Suchalgorithmus finden Sie in meinem anderen Beitrag hier

Wenn Sie hinsichtlich der Dateigröße so zimperlich sind wie ich, können Sie Leistungseinbußen hinnehmen, um die Dateigröße erheblich zu verringern und die Wartbarkeit zu verbessern.

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

function filterArrayByAnotherArray(searchArray, filterArray) {
    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.
        typeof searchArray[0] == "number" &&
        typeof filterArray[0] == "number" &&
        (searchArray[0]|0) === searchArray[0] &&
        (filterArray[0]|0) === filterArray[0]
    ) {
        // if all entries in both arrays are integers
        searchArray.sort(sortIntArray);
        filterArray.sort(sortIntArray);
    } else {
        searchArray.sort(sortAnyArray);
        filterArray.sort(sortAnyArray);
    }
    // Progressive Linear Search
    var i = 0;
    return searchArray.filter(function(currentValue){
        while (filterArray[i] < currentValue) i=i+1|0;
        // +undefined = NaN, which is always false for <, avoiding an infinite loop
        return filterArray[i] !== currentValue;
    });
}

Lassen Sie uns einige JSPerfs untersuchen, um den Geschwindigkeitsunterschied zu beweisen. Für Filtern eines Arrays aus 16 Elementen ist die binäre Suche ungefähr 17% schneller als indexOf, während filterArrayByAnotherArray ungefähr 93% schneller als indexOf ist. Für Filtern eines Arrays aus 256 Elementen ist die binäre Suche ungefähr 291% schneller als der IndexOf, während filterArrayByAnotherArray ungefähr 353% schneller als der IndexOf ist. Für Filtern eines Arrays von 4096 Elementen ist die binäre Suche ungefähr 2655% schneller als indexOf, während filterArrayByAnotherArray ungefähr 4627% schneller als indexOf ist.

3
Jack Giffin

Es gibt viele Antworten auf Ihre Frage, aber ich sehe niemanden, der Lambda-Ausdruck verwendet

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

Der OA kann auch wie folgt in ES6 implementiert werden

ES6:

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

Ein flexibleres Filterarray aus einem anderen Array, das Objekteigenschaften enthält

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

In den folgenden Beispielen wird mit new Set() ein gefiltertes Array erstellt, das nur eindeutige Elemente enthält:

Array mit primitiven Datentypen: String, Number, Boolean, Null, undefined, Symbol:

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

Array mit Objekten als Artikel:

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

Die beste Beschreibung der filter-Funktion lautet https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/filter

Sie sollten einfach die Funktion konditionieren:

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

Sie können nicht auf den Variablenwert zugreifen, bevor er zugewiesen wird

1
suvroc

Sie können den Filter verwenden und dann für die Filterfunktion eine Reduzierung des Filterarrays verwenden, die prüft und true zurückgibt, wenn eine Übereinstimmung gefunden wird, und bei Rückkehr invertieren (!). Die Filterfunktion wird einmal pro Element im Array aufgerufen. Sie vergleichen keines der Elemente in der Funktion in Ihrem Beitrag.

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

Sie können die Filterfunktion so einrichten, dass sie das "Filter-Array" durchläuft.

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

Sie können eine generische filterByIndex () - Funktion schreiben und die Typinferenz in TS verwenden, um den Ärger mit der Rückruffunktion zu speichern:

angenommen, Sie haben Ihr Array [1,2,3,4], das Sie mit den im Array [2,4] angegebenen Indizes filtern möchten ().

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

die byIndex-Funktion erwartet die Elementfunktion und ein Array und sieht folgendermaßen aus:

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

ergebnis ist dann 

filtered = [1,3]
0
lama