Entfernen Sie mehrere Elemente aus dem Array in Javascript / jQuery

117

Ich habe zwei Arrays. Das erste Array enthält einige Werte, während das zweite Array Indizes der Werte enthält, die aus dem ersten Array entfernt werden sollen. Beispielsweise:

var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

Ich möchte die an Indizes vorhandenen Werte 0,2,4aus entfernen valuesArr. Ich dachte, die native spliceMethode könnte helfen, also kam ich auf Folgendes:

$.each(removeValFromIndex,function(index,value){
    valuesArr.splice(value,1);
});

Aber es hat nicht funktioniert, weil nach jedem splicedie Indizes der Werte in valuesArrunterschiedlich waren. Ich könnte dieses Problem lösen, indem ich ein temporäres Array verwende und alle Werte in das zweite Array kopiere, aber ich habe mich gefragt, ob es native Methoden gibt, an die wir mehrere Indizes übergeben können, um Werte aus einem Array zu entfernen.

Ich würde eine jQuery-Lösung bevorzugen. (Nicht sicher, ob ich grephier verwenden kann)

xyz
quelle

Antworten:

254

Es gibt immer die einfache alte forSchleife:

var valuesArr = ["v1","v2","v3","v4","v5"],
    removeValFromIndex = [0,2,4];    

for (var i = removeValFromIndex.length -1; i >= 0; i--)
   valuesArr.splice(removeValFromIndex[i],1);

Gehen Sie removeValFromIndexin umgekehrter Reihenfolge durch , und Sie können .splice()die Indizes der noch zu entfernenden Elemente durcheinander bringen.

Beachten Sie, dass ich oben die Array-Literal-Syntax mit eckigen Klammern verwendet habe, um die beiden Arrays zu deklarieren. Dies ist die empfohlene Syntax, da die new Array()Verwendung möglicherweise verwirrend ist, da sie je nach Anzahl der übergebenen Parameter unterschiedlich reagiert.

BEARBEITEN : Ich habe gerade Ihren Kommentar zu einer anderen Antwort über das Array von Indizes gesehen, die nicht unbedingt in einer bestimmten Reihenfolge vorliegen. Wenn dies der Fall ist, sortieren Sie es einfach in absteigender Reihenfolge, bevor Sie beginnen:

removeValFromIndex.sort(function(a,b){ return b - a; });

Und folgen Sie dem mit einer beliebigen Schleifenmethode $.each().

nnnnnn
quelle
1
wird den Index nicht durcheinander bringen
Muhammad Umer
5
@ MuhammadUmer - Nein, nicht wenn du es richtig machst, was meine Antwort erklärt.
nnnnnn
5
Vielen Dank für das Bewusstsein in umgekehrter Reihenfolge.
Daniel Nalbach
2
+1, ich wusste nicht, dass ich den Spleiß in umgekehrter Reihenfolge ausführen musste, obwohl mein Ansatz anstelle von forEach$.each(rvm.reverse(), function(e, i ) {})
Luis Stanley Jovel
1
Dies wird nur funktionieren, wenn removeValFromIndex in aufsteigender Reihenfolge sortiert ist
Kunal Burangi
24

Hier ist eine, die ich benutze, wenn ich nicht mit lodash / Unterstrich gehe:

while(IndexesToBeRemoved.length) {
    elements.splice(IndexesToBeRemoved.pop(), 1);
}
Dan Ochiana
quelle
Elegante Lösung! Zuerst dachte ich, dass dies nicht funktionieren würde, weil ich dachte, dass Sie jedes Mal, wenn Sie anrufen slice, die zu entfernenden Indizes neu berechnen müssten (-1 ein IndexestoBeRemoved), aber es funktioniert tatsächlich!
Renato Gama
2
Zu klug
Farzad YZ
11
Diese Lösung funktioniert, wenn nur das IndexesToBeRemovedArray nach aufsteigend sortiert ist.
XFG
Diese Indizes werden nach dem ersten Spleißen ungültig.
Shinzou
@shinzou - Nicht wenn IndexesToBeRemovedsortiert (aufsteigend).
nnnnnn
18

Nicht in-placeaber kann mit grepund inArrayFunktionen von gemacht werden jQuery.

var arr = $.grep(valuesArr, function(n, i) {
    return $.inArray(i, removeValFromIndex) ==-1;
});

alert(arr);//arr contains V2, V4

Überprüfen Sie diese Geige.

TheVillageIdiot
quelle
Es wäre (nahe genug) an Ort und Stelle, wenn Sie nur sagtenvaluesArr = $.grep(...);
nnnnnn
1
@nnnnnn ha ha ha Ich war auf dem Weg zu einem Meeting (du weißt, dass sie dich so produktiv machen), also habe ich nicht viel experimentiert.
TheVillageIdiot
1
@ cept0 Warum die Abstimmung? OP fragte nach einer jQuery-Lösung.
Ste77
Ich danke dir sehr! @ TheVillageIdiot
ecorvo
jsfiddler - Fehler 404. Es tut uns wirklich leid, aber es gibt keine solche Seite.
Ash
17

Ich schlage vor, Sie verwenden Array.prototype.filter

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];
valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
})
Саша Давиденко
quelle
Index innerhalb des Filters ... nicht optimal
Alvaro Joao
1
upvote. schneller als die Spleißmethode
lionbigcat
Toll! Jetzt kann ich schlafen :)
Firmansyah
7
function filtermethod(element, index, array) {  
    return removeValFromIndex.find(index)
}  
var result = valuesArr.filter(filtermethod);

Die MDN-Referenz finden Sie hier

riship89
quelle
@ riship89 Die Geige ist unten
mate64
@ Karna: Geige ist unten
riship89
1
Bitte beachten Sie, dass Array.prototype.find zum Zeitpunkt des Schreibens (Juni 2014) Teil des aktuellen ES6-Entwurfs ist und nur in der aktuellen Firefox
Olli K
6

In reinem JS können Sie das Array rückwärts durchlaufen, um die splice()Indizes der Elemente in der nächsten Schleife nicht durcheinander zu bringen:

for (var i = arr.length - 1; i >= 0; i--) {
    if ( yuck(arr[i]) ) {
        arr.splice(i, 1);
    }
}
Watchduck
quelle
Funktioniert nicht yuck ist keine Funktion, daher wird davon ausgegangen, dass es sich um den Index unerwünschter Elementindizes handelt. Yuck [arr [i]]
DavChana
5

Es fühlt sich notwendig an, eine Antwort mit der O(n)Zeit zu posten :). Das Problem bei der Spleißlösung besteht darin, dass jeder Aufruf einige Zeit in Anspruch nimmt, da die zugrunde liegende Implementierung des Arrays buchstäblich ein Array ist . Dies ist am ausgeprägtesten, wenn wir ein Beispiel einrichten, um dieses Verhalten auszunutzen:spliceO(n)

var n = 100
var xs = []
for(var i=0; i<n;i++)
  xs.push(i)
var is = []
for(var i=n/2-1; i>=0;i--)
  is.push(i)

Dies entfernt Elemente von der Mitte bis zum Start, daher zwingt jedes Entfernen die js-Engine, n/2Elemente zu kopieren . Wir haben (n/2)^2insgesamt Kopieroperationen , die quadratisch sind.

Die Spleißlösung (vorausgesetzt, sie isist bereits in absteigender Reihenfolge sortiert, um Gemeinkosten zu beseitigen) sieht folgendermaßen aus:

for(var i=0; i<is.length; i++)
  xs.splice(is[i], 1)

Es ist jedoch nicht schwer, eine lineare Zeitlösung zu implementieren, indem das Array von Grund auf neu erstellt wird und eine Maske verwendet wird, um festzustellen, ob wir Elemente kopieren oder nicht (sort wird dies verschieben O(n)log(n)). Das Folgende ist eine solche Implementierung (nicht, dass sie maskaus Geschwindigkeitsgründen boolesch invertiert ist):

var mask = new Array(xs.length)
for(var i=is.length - 1; i>=0; i--)
  mask[is[i]] = true
var offset = 0
for(var i=0; i<xs.length; i++){
  if(mask[i] === undefined){
    xs[offset] = xs[i]
    offset++
  }
}
xs.length = offset

Ich habe dies auf jsperf.com ausgeführt und selbst n=100die Spleißmethode ist um 90% langsamer. Für größere wird ndieser Unterschied viel größer sein.

Simonzack
quelle
5

Eine einfache und effiziente Lösung (lineare Komplexität) mit Filter und Set :

const valuesArr = ['v1', 'v2', 'v3', 'v4', 'v5'];   
const removeValFromIndex = [0, 2, 4];

const indexSet = new Set(removeValFromIndex);

const arrayWithValuesRemoved = valuesArr.filter((value, i) => !indexSet.has(i));

console.log(arrayWithValuesRemoved);

Der große Vorteil dieser Implementierung besteht darin, dass die Set-Lookup-Operation ( hasFunktion) eine konstante Zeit benötigt und beispielsweise schneller als die Antwort von nevace ist.

Alberto Trindade Tavares
quelle
@ MichaelPaccione Gerne helfen :)
Alberto Trindade Tavares
4

Quick ES6 One Liner:

const valuesArr = new Array("v1","v2","v3","v4","v5");   
const removeValFromIndex = new Array(0,2,4);

const arrayWithValuesRemoved = valuesArr.filter((value, i) => removeValFromIndex.includes(i))
Nevace
quelle
Ihr Code sollte schneller ausgeführt werden, wenn Sie removeValFromIndexa erstellen Set()und removeValFromIndex.hasstattdessen verwenden includes.
Boris
3

Dies funktioniert gut für mich und funktioniert auch beim Löschen aus einem Array von Objekten:

var array = [ 
    { id: 1, name: 'bob', faveColor: 'blue' }, 
    { id: 2, name: 'jane', faveColor: 'red' }, 
    { id: 3, name: 'sam', faveColor: 'blue' }
];

// remove people that like blue

array.filter(x => x.faveColor === 'blue').forEach(x => array.splice(array.indexOf(x), 1));

Es gibt möglicherweise eine kürzere und effizientere Möglichkeit, dies zu schreiben, aber dies funktioniert.

StuartMc
quelle
2

Eine einfache Lösung mit ES5. Dies scheint heutzutage für die meisten Anwendungen angemessener zu sein, da sich viele nicht mehr auf jQuery usw. verlassen möchten.

Wenn die zu entfernenden Indizes in aufsteigender Reihenfolge sortiert sind:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [0, 2, 4]; // ascending

removeValFromIndex.reverse().forEach(function(index) {
  valuesArr.splice(index, 1);
});

Wenn die zu entfernenden Indizes nicht sortiert sind:

var valuesArr = ["v1", "v2", "v3", "v4", "v5"];   
var removeValFromIndex = [2, 4, 0];  // unsorted

removeValFromIndex.sort(function(a, b) { return b - a; }).forEach(function(index) {
  valuesArr.splice(index, 1);
});
Kaspar Fenner
quelle
1

Sie können durch das Ersetzen Sie den Code korrigieren removeValFromIndexmit removeValFromIndex.reverse(). Wenn nicht garantiert wird, dass dieses Array aufsteigende Reihenfolge verwendet, können Sie stattdessen verwenden removeValFromIndex.sort(function(a, b) { return b - a }).

Minopret
quelle
Sieht für mich gut aus - jsfiddle.net/mrtsherman/gDcFu/2 . Obwohl dies die Annahme macht, dass die Entfernungsliste in Ordnung ist.
Mrtsherman
@minopret: Danke, aber es wird nur funktionieren, wenn die Indizes removeValFromIndexin aufsteigender Reihenfolge sind.
XYZ
1

Wenn Sie underscore.js verwenden , können Sie damit _.filter()Ihr Problem lösen.

var valuesArr = new Array("v1","v2","v3","v4","v5");
var removeValFromIndex = new Array(0,2,4);
var filteredArr = _.filter(valuesArr, function(item, index){
                  return !_.contains(removeValFromIndex, index);
                });

Wenn Sie versuchen, Elemente mithilfe einer Liste von Elementen anstelle von Indizes zu entfernen, können Sie außerdem einfach Folgendes verwenden _.without():

var valuesArr = new Array("v1","v2","v3","v4","v5");
var filteredArr = _.without(valuesArr, "V1", "V3");

Jetzt filteredArrsollte es sein["V2", "V4", "V5"]

Johnny Zhao
quelle
Wie enthält ist in Unterstrich implementiert ... seien Sie vorsichtig, wenn es IndexOf innerhalb des Filters entspricht ... überhaupt nicht optimal ...
Alvaro Joao
1

filter + indexOf (IE9 +):

function removeMany(array, indexes) {
  return array.filter(function(_, idx) {
    return indexes.indexOf(idx) === -1;
  });
}); 

Oder mit ES6 Filter + Find (Edge +):

function removeMany(array, indexes = []) {
  return array.filter((_, idx) => indexes.indexOf(idx) === -1)
}
Daviestar
quelle
Index innerhalb des Filters ... nicht optimal
Alvaro Joao
1

Hier ist ein Quickie.

function removeFromArray(arr, toRemove){
    return arr.filter(item => toRemove.indexOf(item) === -1)
}

const arr1 = [1, 2, 3, 4, 5, 6, 7]
const arr2 = removeFromArray(arr1, [2, 4, 6]) // [1,3,5,7]
Merrick Kavolsky
quelle
Index innerhalb des Filters ... nicht optimal
Alvaro Joao
0

Klingt so, als ob Übernehmen genau das sein könnte, wonach Sie suchen.
Vielleicht würde so etwas funktionieren?

Array.prototype.splice.apply(valuesArray, removeValFromIndexes );
rauben
quelle
Die .splice()Methode erwartet jedoch keine Liste der zu entfernenden Elemente, sondern einen einzelnen Index des Elements, bei dem mit dem Entfernen begonnen werden soll, gefolgt von der Anzahl der zu entfernenden Elemente ...
nnnnnn
0

Für mehrere Artikel oder Einzelartikel:

Ich schlage vor, Sie verwenden Array.prototype.filter

Verwenden Sie indexOf niemals, wenn Sie den Index bereits kennen!:

var valuesArr = ["v1","v2","v3","v4","v5"];
var removeValFrom = [0, 2, 4];

valuesArr = valuesArr.filter(function(value, index) {
     return removeValFrom.indexOf(index) == -1;
}); // BIG O(N*m) where N is length of valuesArr and m is length removeValFrom

Machen:

mit Hashes ... mit Array.prototype.map

  var valuesArr = ["v1","v2","v3","v4","v5"];
  var removeValFrom = {};
  ([0, 2, 4]).map(x=>removeValFrom[x]=1); //bild the hash.
  valuesArr = valuesArr.filter(function(value, index) {
      return removeValFrom[index] == 1;
  }); // BIG O(N) where N is valuesArr;
Alvaro Joao
quelle
0
var valuesArr = new Array("v1","v2","v3","v4","v5");   
var removeValFromIndex = new Array(0,2,4);

console.log(valuesArr)
let arr2 = [];

for (let i = 0; i < valuesArr.length; i++){
  if (    //could also just imput this below instead of index value
    valuesArr[i] !== valuesArr[0] && // "v1" <--
    valuesArr[i] !== valuesArr[2] && // "v3" <--
    valuesArr[i] !== valuesArr[4]    // "v5" <--
  ){
    arr2.push(valuesArr[i]);
  }
}

console.log(arr2);

Das funktioniert. Sie würden dabei jedoch ein neues Array erstellen. Ich bin mir nicht sicher, ob Sie das wollen oder nicht, aber technisch gesehen wäre es ein Array, das nur die gewünschten Werte enthält.


quelle
-1

Sie können versuchen, dies zu verwenden. delete array[index]Dadurch wird das Element nicht vollständig entfernt, sondern der Wert auf festgelegt undefined.

Henesnarfel
quelle
Danke, aber ich möchte die Elemente entfernen.
XYZ
-1

Sie können ein SetArray aus dem Array erstellen und dann ein Array aus dem Set erstellen.

const array = [1, 1, 2, 3, 5, 5, 1];
const uniqueArray = [...new Set(array)];
console.log(uniqueArray); // Result: [1, 2, 3, 5]
Mohib
quelle