Hvordan kan jeg fjerne et spesifikt element fra en matrise i JavaScript?


Hvordan fjerner jeg en spesifikk verdi fra et array? Noe som dette:

array.remove(value);

Begrensninger: Jeg må bruke ren JavaScript. Rammeverk er ikke tillatt.

Svar #1

Finn indeksen til array-elementet du vil fjerne ved å bruke indexOf, og fjern deretter den indeksen med splice.

Splice()-metoden endrer innholdet i en matrise ved å fjerne eksisterende elementer og/eller legge til nye elementer.

const array = [2, 5, 9];

console.log(array);

const index = array.indexOf(5);
if (index > -1) { // only splice array when item is found
  array.splice(index, 1); // 2nd parameter means remove one item only
}

// array = [2, 9]
console.log(array);

Den andre parameteren til splice er antall elementer som skal fjernes. Merk at splice endrer arrayen direkte og returnerer en ny array som inneholder elementene som har blitt fjernet.


For fullstendighet, her er funksjonene. Den første funksjonen fjerner bare ett enkelt tilfelle (f.eks. å fjerne det første treffet av 5 fra [2,5,9,1,5,8,5]), mens den andre funksjonen fjerner alle forekomster:

function removeItemOnce(arr, value) {
  var index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}

function removeItemAll(arr, value) {
  var i = 0;
  while (i < arr.length) {
    if (arr[i] === value) {
      arr.splice(i, 1);
    } else {
      ++i;
    }
  }
  return arr;
}
// Usage
console.log(removeItemOnce([2,5,9,1,5,8,5], 5))
console.log(removeItemAll([2,5,9,1,5,8,5], 5))

I TypeScript kan disse funksjonene forbli typesikre med en typeparameter:

function removeItem<T>(arr: Array<T>, value: T): Array<T> {
  const index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}

Svar #2

  • Gjør det enkelt, intuitivt og tydelig (Occams barberkniv)
  • Gjør det uforanderlig (originalen på arrayet forblir uendret)
  • Gjør det med standard JavaScript-funksjoner, hvis nettleseren din ikke støtter dem - bruk polyfill

I dette kodeeksemplet bruker jeg array.filter(...)-funksjonen for å fjerne uønskede elementer fra en array. Denne funksjonen endrer ikke den originale arrayen og oppretter en ny. Hvis nettleseren din ikke støtter denne funksjonen (f.eks. Internet Explorer før versjon 9, eller Firefox før versjon 1.5), bør du vurdere å polyfill med core-js.

Vær imidlertid oppmerksom på at det å lage et nytt array hver gang fører til en stor ytelsestap. Hvis listen er veldig stor (tenk 10k+ elementer), bør du vurdere å bruke andre metoder.

Fjerner element (ECMA-262 utgave 5-kode, også kjent som gammeldags JavaScript)

var value = 3

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

arr = arr.filter(function(item) {
    return item !== value
})

console.log(arr)
// [ 1, 2, 4, 5 ]

Fjerner element (ECMAScript 6-kode)

let value = 3

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => item !== value)

console.log(arr)
// [ 1, 2, 4, 5 ]

VIKTIG ECMAScript 6 () => {} pilfunksjonssyntaks støttes ikke i det hele tatt i Internet Explorer, Chrome før versjon 45, Firefox før versjon 22, og Safari før versjon 10. For å bruke ECMAScript 6-syntaks i gamle nettlesere kan du bruke BabelJS.


Fjern flere elementer (ECMAScript 7-kode)

En ytterligere fordel med denne metoden er at du kan fjerne flere elementer

let forDeletion = [2, 3, 5]

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => !forDeletion.includes(item))
// !!! Read below about array.includes(...) support !!!

console.log(arr)
// [ 1, 4 ]

VIKTIG array.includes(...) funksjonen støttes ikke i det hele tatt i Internet Explorer, Chrome før versjon 47, Firefox før versjon 43, Safari før versjon 9, og Edge før versjon 14, men du kan polyfille med core-js.

Fjern flere elementer (kanskje i fremtiden)

Hvis forslaget «This-Binding Syntax» noen gang blir akseptert, vil du kunne gjøre dette:

// array-lib.js

export function remove(...forDeletion) {
    return this.filter(item => !forDeletion.includes(item))
}

// main.js

import { remove } from './array-lib.js'

let arr = [1, 2, 3, 4, 5, 3]

// :: This-Binding Syntax Proposal
// using "remove" function as "virtual method"
// without extending Array.prototype
arr = arr::remove(2, 3, 5)

console.log(arr)
// [ 1, 4 ]

Prøv det selv i BabelJS :)

Referanse

  • Array.prototype.includes
  • Funksjonell sammensetning

Svar #3

Jeg vet ikke hvordan du forventer at array.remove(int) skal oppføre seg. Det er tre muligheter jeg kan tenke meg at du kanskje ønsker.

For å fjerne et element fra en matrise på en indeks i:

array.splice(i, 1);

Hvis du vil fjerne hvert element med verdien number fra arrayen:

for(var i = array.length - 1; i >= 0; i--) {
    if(array[i] === number) {
       array.splice(i, 1);
    }
}

Hvis du bare vil at elementet på indeks i ikke lenger skal eksistere, men du ikke vil at indeksene til de andre elementene skal endres:

delete array[i];

Svar #4

Det avhenger av om du vil beholde et tomt rom eller ikke.

Hvis du ønsker en tom plass:

array[index] = undefined;

Hvis du ikke vil ha en tom plass:

// To keep the original:
// oldArray = [...array];

// This modifies the array.
array.splice(index, 1);

Og hvis du trenger verdien av det elementet, kan du bare lagre elementet fra den returnerte arrayen:

var value = array.splice(index, 1)[0];

Hvis du vil fjerne elementer fra enten starten eller slutten av arrayet, kan du bruke array.pop() for det siste eller array.shift() for det første (begge returnerer også verdien av elementet).

Hvis du ikke kjenner indeksen til elementet, kan du bruke array.indexOf(item) for å få den (i en if() for å få ett element eller i en while() for å få alle). array.indexOf(item) returnerer enten indeksen eller -1 hvis det ikke finnes.

Svar #5

Det finnes to hovedtilnærminger

  1. splice(): anArray.splice(index, 1);

    let fruits = ['Apple', 'Banana', 'Mango', 'Orange']
    let removed = fruits.splice(2, 1);
    // fruits is ['Apple', 'Banana', 'Orange']
    // removed is ['Mango']
    
  2. slett: slett anArray[index];

    let fruits = ['Apple', 'Banana', 'Mango', 'Orange']
    let removed = delete fruits(2);
    // fruits is ['Apple', 'Banana', undefined, 'Orange']
    // removed is true
    

Vær forsiktig når du bruker delete for et array. Det er bra for å slette egenskaper til objekter, men ikke så bra for arrays. Det er bedre å bruke splice for arrays.

Husk at når du bruker delete på et array, kan du få feil resultater for anArray.length. Med andre ord, delete fjerner elementet, men oppdaterer ikke verdien av length-egenskapen.

Du kan også forvente å ha hull i indeksnumrene etter å ha brukt delete, for eksempel kan du ende opp med å ha indeksene 1, 3, 4, 8, 9 og 11 og lengden som den var før du brukte delete. I så fall vil alle indekserte for-løkker krasje, siden indeksene ikke lenger er sekvensielle.

Hvis du av en eller annen grunn er tvunget til å bruke delete, bør du bruke for each-løkker når du må gå gjennom arrayer. Faktisk bør du alltid unngå å bruke indekserte for-løkker, hvis mulig. På den måten vil koden være mer robust og mindre utsatt for problemer med indekser.

Svar #6

Array.prototype.removeByValue = function (val) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] === val) {
      this.splice(i, 1);
      i--;
    }
  }
  return this;
}

var fruits = ['apple', 'banana', 'carrot', 'orange'];
fruits.removeByValue('banana');

console.log(fruits);
// -> ['apple', 'carrot', 'orange']

Svar #7

Det er ikke nødvendig å bruke indexOf eller splice. Det fungerer imidlertid bedre hvis du bare vil fjerne én forekomst av et element.

Finn og flytt (flytt):

function move(arr, val) {
  var j = 0;
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i] !== val) {
      arr[j++] = arr[i];
    }
  }
  arr.length = j;
}

Bruk indexOf og splice (indexof):

function indexof(arr, val) {
  var i;
  while ((i = arr.indexOf(val)) != -1) {
    arr.splice(i, 1);
  }
}

Bruk bare splice (splice):

function splice(arr, val) {
  for (var i = arr.length; i--;) {
    if (arr[i] === val) {
      arr.splice(i, 1);
    }
  }
}

Kjøretider på Node.js for et array med 1000 elementer (gjennomsnitt over 10 000 kjøringer):

indexof er omtrent 10 ganger tregere enn move. Selv om det forbedres ved å fjerne kall til indexOf i splice, presterer det mye dårligere enn move.

Remove all occurrences:
    move 0.0048 ms
    indexof 0.0463 ms
    splice 0.0359 ms

Remove first occurrence:
    move_one 0.0041 ms
    indexof_one 0.0021 ms

Svar #8

Dette gir et predikat i stedet for en verdi.

MERK: det vil oppdatere den gitte arrayen, og returnere de berørte radene.

Bruk

var removed = helper.remove(arr, row => row.id === 5 );

var removed = helper.removeAll(arr, row => row.name.startsWith('BMW'));

Definisjon

var helper = {
 // Remove and return the first occurrence

 remove: function(array, predicate) {
  for (var i = 0; i < array.length; i++) {
   if (predicate(array[i])) {
    return array.splice(i, 1);
   }
  }
 },

 // Remove and return all occurrences

 removeAll: function(array, predicate) {
  var removed = [];

  for (var i = 0; i < array.length; ) {
   if (predicate(array[i])) {
    removed.push(array.splice(i, 1));
    continue;
   }
   i++;
  }
  return removed;
 },
};

Svar #9

Du kan gjøre det enkelt med filtermetoden:

function remove(arrOriginal, elementToRemove){
    return arrOriginal.filter(function(el){return el !== elementToRemove});
}
console.log(remove([1, 2, 1, 0, 3, 1, 4], 1));

Dette fjerner alle elementene fra arrayet og fungerer også raskere enn en kombinasjon av slice og indexOf.

Svar #10

John Resig la ut en god implementering:

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

Hvis du ikke vil utvide et globalt objekt, kan du gjøre noe som følgende i stedet:

// Array Remove - By John Resig (MIT Licensed)
Array.remove = function(array, from, to) {
    var rest = array.slice((to || from) + 1 || array.length);
    array.length = from < 0 ? array.length + from : from;
    return array.push.apply(array, rest);
};

Men hovedgrunnen til at jeg legger ut dette er å advare brukere mot den alternative implementeringen som ble foreslått i kommentarene på den siden (14. desember 2007):

Array.prototype.remove = function(from, to) {
  this.splice(from, (to=[0, from || 1, ++to - from][arguments.length]) < 0 ? this.length + to : to);
  return this.length;
};

Det ser ut til å fungere godt i starten, men gjennom en smertefull prosess oppdaget jeg at det mislykkes når man prøver å fjerne nest siste element i en matrise. For eksempel, hvis du har en matrise med 10 elementer og du prøver å fjerne det 9. elementet med dette:

myArray.remove(8);

Du ender opp med et 8-elementers array. Jeg vet ikke hvorfor, men jeg har bekreftet at Johns opprinnelige implementering ikke har dette problemet.

Svar #11

Underscore.js kan brukes til å løse problemer med flere nettlesere. Den bruker innebygde nettlesermetoder hvis de er til stede. Hvis de mangler, som i tilfelle eldre versjoner av Internet Explorer, bruker den sine egne tilpassede metoder.

Et enkelt eksempel på å fjerne elementer fra en array (fra nettsiden):

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1); // => [2, 3, 4]

Svar #12

Hvis du vil ha et nytt array med de slettede posisjonene fjernet, kan du alltid slette det spesifikke elementet og filtrere ut arrayet. Det kan være nødvendig med en utvidelse av array-objektet for nettlesere som ikke implementerer filter-metoden, men på lang sikt er det enklere siden alt du gjør er dette:

var my_array = [1, 2, 3, 4, 5, 6];
delete my_array[4];
console.log(my_array.filter(function(a) {
  return typeof a !== 'undefined';
}));

Det skal vise [1, 2, 3, 4, 6].

Svar #13

Sjekk ut denne koden. Den fungerer i alle store nettlesere.

remove_item = function(arr, value) {
  var b = '';
  for (b in arr) {
    if (arr[b] === value) {
      arr.splice(b, 1);
      break;
    }
  }
  return arr;
};

var array = [1,3,5,6,5,9,5,3,55];
var res = remove_item(array,5);
console.log(res);

Svar #14

Du kan bruke lodash _.pull (endrer array), _.pullAt (endrer array) eller _.without (endrer ikke array),

var array1 = ['a', 'b', 'c', 'd']
_.pull(array1, 'c')
console.log(array1) // ['a', 'b', 'd']

var array2 = ['e', 'f', 'g', 'h']
_.pullAt(array2, 0)
console.log(array2) // ['f', 'g', 'h']

var array3 = ['i', 'j', 'k', 'l']
var newArray = _.without(array3, 'i') // ['j', 'k', 'l']
console.log(array3) // ['i', 'j', 'k', 'l']

Svar #15

ES6 & uten mutasjon: (oktober 2016)

const removeByIndex = (list, index) => [
  ...list.slice(0, index),
  ...list.slice(index + 1)
];
         
output = removeByIndex([33, 22, 11, 44], 1); // -> [33, 11, 44]
      
console.log(output);

Svar #16

Ytelse

I dag (2019-12-09) gjennomfører jeg ytelsestester på macOS v10.13.6 (High Sierra) for utvalgte løsninger. Jeg viser delete (A), men jeg bruker det ikke i sammenligning med andre metoder, fordi det etterlot tomt plass i arrayet.

Konklusjonene

  • den raskeste løsningen er array.splice (C) (bortsett fra Safari for små arrays hvor den har den andre tiden)
  • for store arrays, array.slice+splice (H) er den raskeste uforanderlige løsningen for Firefox og Safari; Array.from (B) er raskest i Chrome
  • muterbare løsninger er vanligvis 1,5x-6x raskere enn immutables
  • for små tabeller på Safari er det overraskende at den mutable løsningen (C) er tregere enn den immutable løsningen (G)

Detaljer

I tester fjerner jeg det midterste elementet fra arrayet på forskjellige måter. A, C-løsningene er på stedet. B, D, E, F, G, H-løsningene er uforanderlige.

Resultater for et array med 10 elementer

I Chrome er array.splice (C) den raskeste løsning på stedet. array.filter (D) er den raskeste uforanderlige løsningen. Den tregeste er array.slice (F). Du kan utføre testen på din maskin her.

Resultater for et array med 1.000.000 elementer

I Chrome er array.splice (C) den raskeste løsning på stedet (den delete (C) er omtrent like rask - men den etterlot et tomt hull i arrayen (så den utfører ikke en «full fjerning»)). array.slice-splice (H) er den raskeste uforanderlige løsningen. Den tregeste er array.filter (D og E). Du kan utføre testen på maskinen din her.

var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var log = (letter,array) => console.log(letter, array.join `,`);

function A(array) {
  var index = array.indexOf(5);
  delete array[index];
  log('A', array);
}

function B(array) {
  var index = array.indexOf(5);
  var arr = Array.from(array);
  arr.splice(index, 1)
  log('B', arr);
}

function C(array) {
  var index = array.indexOf(5);
  array.splice(index, 1);
  log('C', array);
}

function D(array) {
  var arr = array.filter(item => item !== 5)
  log('D', arr);
}

function E(array) {
  var index = array.indexOf(5);
  var arr = array.filter((item, i) => i !== index)
  log('E', arr);
}

function F(array) {
  var index = array.indexOf(5);
  var arr = array.slice(0, index).concat(array.slice(index + 1))
  log('F', arr);
}

function G(array) {
  var index = array.indexOf(5);
  var arr = [...array.slice(0, index), ...array.slice(index + 1)]
  log('G', arr);
}

function H(array) {
  var index = array.indexOf(5);
  var arr = array.slice(0);
  arr.splice(index, 1);
  log('H', arr);
}

A([...a]);
B([...a]);
C([...a]);
D([...a]);
E([...a]);
F([...a]);
G([...a]);
H([...a]);
This snippet only presents code used in performance tests - it does not perform tests itself.

Sammenligning for nettlesere: Chrome v78.0.0, Safari v13.0.4 og Firefox v71.0.0

Svar #17

OK, for eksempel har du matrisa under:

var num = [1, 2, 3, 4, 5];

Og vi vil slette nummer 4. Du kan enkelt bruke koden nedenfor:

num.splice(num.indexOf(4), 1); // num will be [1, 2, 3, 5];

Hvis du gjenbruker denne funksjonen, skriver du en gjenbrukbar funksjon som vil bli knyttet til den native array-funksjonen som vist nedenfor:

Array.prototype.remove = Array.prototype.remove || function(x) {
  const i = this.indexOf(x);
  if(i===-1)
      return;
  this.splice(i, 1); // num.remove(5) === [1, 2, 3];
}

Men hva hvis du har følgende array i stedet med noen [5] i arrayet?

var num = [5, 6, 5, 4, 5, 1, 5];

Vi trenger en løkke for å sjekke dem alle, men en enklere og mer effektiv måte er å bruke innebygde JavaScript-funksjoner, så vi skriver en funksjon som bruker et filter som nedenfor i stedet:

const _removeValue = (arr, x) => arr.filter(n => n!==x);
//_removeValue([1, 2, 3, 4, 5, 5, 6, 5], 5) // Return [1, 2, 3, 4, 6]

Det finnes også tredjepartsbiblioteker som hjelper deg med dette, som Lodash eller Underscore. For mer informasjon, se på lodash _.pull, _.pullAt eller _.without.

Svar #18

Jeg er ganske ny på JavaScript og trengte denne funksjonaliteten. Jeg skrev bare dette:

function removeFromArray(array, item, index) {
  while((index = array.indexOf(item)) > -1) {
    array.splice(index, 1);
  }
}

Da når jeg vil bruke det:

// Set-up some dummy data
var dummyObj = { name: "meow" };
var dummyArray = [dummyObj, "item1", "item1", "item2"];

// Remove the dummy data
removeFromArray(dummyArray, dummyObj);
removeFromArray(dummyArray, "item2");

Output - Som forventet: ["item1", "item1"]

Du kan ha andre behov enn meg, så du kan enkelt endre det for å passe dem. Jeg håper dette hjelper noen.

Svar #19

Du bør aldri endre på arrayen din da dette strider mot funksjonell programmeringsmønster. Du kan lage en ny array uten å referere til den du vil endre data i ved å bruke ECMAScript 6-metoden filter.

var myArray = [1, 2, 3, 4, 5, 6];

Anta at du vil fjerne 5 fra arrayet, du kan enkelt gjøre det slik:

myArray = myArray.filter(value => value !== 5);

Dette vil gi deg en ny array uten verdien du ønsket å fjerne. Så resultatet vil være:

 [1, 2, 3, 4, 6]; // 5 has been removed from this array

For videre forståelse kan du lese MDN-dokumentasjonen om Array.filter.

Svar #20

En mer moderne ECMAScript 2015 (tidligere kjent som Harmony eller ES 6) tilnærming. Gitt:

const items = [1, 2, 3, 4];
const index = 2;

Så :

items.filter((x, i) => i !== index);

Avkastning:

[1, 2, 4]

Du kan bruke Babel og en polyfill-tjeneste for å sikre at dette er godt støttet på tvers av nettlesere.

Svar #21

Array.prototype.removeItem = function(a) {
    for (i = 0; i < this.length; i++) {
        if (this[i] == a) {
            for (i2 = i; i2 < this.length - 1; i2++) {
                this[i2] = this[i2 + 1];
            }
            this.length = this.length - 1
            return;
        }
    }
}

var recentMovies = ['Iron Man', 'Batman', 'Superman', 'Spiderman'];
recentMovies.removeItem('Superman');

Svar #22

2021 OPPDATERING

Spørsmålet ditt handler om hvordan man fjerner et spesifikt element fra et array. Med spesifikt element refererer du til et tall, for eksempel å fjerne tallet 5 fra arrayet. Så vidt jeg forstår, leter du etter noe som dette:

// PSEUDOCODE, SCROLL FOR COPY-PASTE CODE
[1,2,3,4,5,6,8,5].remove(5) // result: [1,2,3,4,6,8]

Når det gjelder 2021, er den beste måten å oppnå det på å bruke array-filterfunksjonen:

const input = [1,2,3,4,5,6,8,5];
const removeNumber = 5;
const result = input.filter(
    item => item != removeNumber
);

Eksemplet ovenfor bruker array.prototype.filter-funksjonen. Den itererer over alle elementene i arrayen, og returnerer kun de som tilfredsstiller pilfunksjonen. Som et resultat forblir den gamle arrayen intakt, mens en ny array kalt result inneholder alle elementene som ikke er lik fem. Du kan teste det selv på nett.

Du kan visualisere array.prototype.filter slik:

Vurderinger

Kodekvalitet

Array.prototype.filter er langt den mest lesbare metoden for å fjerne et tall i dette tilfellet. Den gir liten plass for feil og bruker kjernefunksjonalitet i JS.

Hvorfor ikke array.prototype.map?

Array.prototype.map blir noen ganger vurdert som et alternativ til array.prototype.filter for det brukstilfellet. Men det bør ikke brukes. Årsaken er at array.prototype.filter konseptuelt brukes til å filtrere elementer som tilfredsstiller en pilfunksjon (akkurat det vi trenger), mens array.prototype.map brukes til å transformere elementer. Siden vi ikke endrer elementene mens vi itererer over dem, er den riktige funksjonen å bruke array.prototype.filter.

Støtte

Per i dag (11.4.2022) støtter 94,08 % av internettbrukernes nettlesere array.prototype.filter. Så generelt sett er det trygt å bruke. Imidlertid støtter ikke IE6 - 8 det. Så hvis ditt brukstilfelle krever støtte for disse nettleserne, finnes det en fin polyfill laget av Chris Ferdinanti.

Ytelse

Array.prototype.filter er flott for de fleste bruksområder. Men hvis du ser etter noen ytelsesforbedringer for avansert databehandling, kan du utforske noen andre alternativer, som å bruke ren for. Et annet godt alternativ er å revurdere om arrayen du behandler virkelig må være så stor. Det kan være et tegn på at JavaScript bør motta et redusert array for behandling fra datakilden.

Et referansepunkt for de forskjellige mulighetene: https://jsben.ch/C5MXz

Svar #23

Jeg liker denne ene-linjen:

arr.includes(val) && arr.splice(arr.indexOf(val), 1)
  • Fjerner bare én verdi av gangen.
  • Støtter fjerning av verdier som null eller undefined eller objektreferanser - men ikke NaN (indexOf støtter ikke NaN).
  • Rask for store arrays (>million): includes+indexOf+splice kombinert er ~10 ganger raskere enn filter eller for.

Som en prototype

// remove by value. return true if value found and removed, false otherwise
Array.prototype.removeByValue = function(val)
{
    return this.includes(val) && !!this.splice(this.indexOf(val), 1);
}

(Ja, jeg har lest alle andre svar og kunne ikke finne ett som kombinerer includes og splice på samme linje.)

Svar #24

Jeg testet splice og filter for å se hvilken som er raskere:

let someArr = [...Array(99999).keys()] 

console.time('filter')
someArr.filter(x => x !== 6666)
console.timeEnd('filter')

console.time('splice by indexOf')
someArr.splice(someArr.indexOf(6666), 1)
console.timeEnd('splice by indexOf')

På maskinen min er splice raskere. Dette gir mening, siden splice bare redigerer en eksisterende matrise, mens filter lager en ny matrise.

Når det er sagt, er filter logisk sett renere (lettere å lese) og passer bedre inn i en kodestil som bruker uforanderlig tilstand. Så det er opp til deg om du vil gjøre den avveiningen.

REDIGER :

For å være tydelig, gjør splice og filter forskjellige ting: splice redigerer et array, mens filter lager et nytt. Men begge kan brukes for å få et array med et gitt element fjernet.

Svar #25

Jeg støtte også på situasjonen der jeg måtte fjerne et element fra Array. .indexOf fungerte ikke i Internet Explorer, så jeg deler min fungerende jQuery.inArray()-løsning:

var index = jQuery.inArray(val, arr);
if (index > -1) {
    arr.splice(index, 1);
    //console.log(arr);
}

Svar #26

Du kan iterere over hvert array-element og splice det hvis det finnes i ditt array.

function destroy(arr, val) {
    for (var i = 0; i < arr.length; i++) if (arr[i] === val) arr.splice(i, 1);
    return arr;
}

Svar #27

Jeg synes mange av JavaScript-instruksjonene ikke er godt gjennomtenkt for funksjonell programmering. Splice returnerer det slettede elementet, mens du som oftest trenger den reduserte arrayen. Dette er dårlig.

Forestill deg at du gjør et rekursivt kall og må sende et array med ett element mindre, sannsynligvis uten det nåværende indekserte elementet. Eller forestill deg at du gjør et annet rekursivt kall og må sende et array med et element lagt til.

I ingen av disse tilfellene kan du gjøre myRecursiveFunction(myArr.push(c)) eller myRecursiveFunction(myArr.splice(i,1)). Den første idioten vil faktisk sende lengden på arrayen, og den andre idioten vil sende det slettede elementet som en parameter.

Så det jeg faktisk gjør... For å slette et element i en array og sende resultatet til en funksjon som en parameter samtidig gjør jeg som følger

myRecursiveFunction(myArr.slice(0,i).concat(a.slice(i+1)))

Når det gjelder push, det er mer tullete... likte jeg det.

myRecursiveFunction((myArr.push(c),myArr))

Jeg tror at i et ordentlig funksjonelt språk må en metode som muterer objektet den blir kalt på, returnere en referanse til selve objektet som resultat.

Svar #28

2017-05-08

De fleste av de gitte svarene fungerer for streng sammenligning, noe som betyr at begge objektene refererer til det nøyaktige samme objektet i minnet (eller er primitive typer), men ofte vil man fjerne et ikke-primært objekt fra et array som har en viss verdi. For eksempel, hvis du gjør et kall til en server og vil sjekke et hentet objekt mot et lokalt objekt.

const a = {'field': 2} // Non-primitive object
const b = {'field': 2} // Non-primitive object with same value
const c = a            // Non-primitive object that reference the same object as "a"

assert(a !== b) // Don't reference the same item, but have same value
assert(a === c) // Do reference the same item, and have same value (naturally)

//Note: there are many alternative implementations for valuesAreEqual
function valuesAreEqual (x, y) {
   return  JSON.stringify(x) === JSON.stringify(y)
}


//filter will delete false values
//Thus, we want to return "false" if the item
// we want to delete is equal to the item in the array
function removeFromArray(arr, toDelete){
    return arr.filter(target => {return !valuesAreEqual(toDelete, target)})
}

const exampleArray = [a, b, b, c, a, {'field': 2}, {'field': 90}];
const resultArray = removeFromArray(exampleArray, a);

//resultArray = [{'field':90}]

Det finnes alternative/raskere implementasjoner for valuesAreEqual, men dette fungerer. Du kan også bruke en tilpasset sammenligner hvis du har et spesifikt felt du vil sjekke (for eksempel en hentet UUID mot en lokal UUID).

Merk også at dette er en funksjonell operasjon, noe som betyr at den ikke endrer den opprinnelige arrayen.

Svar #29

I ES6 gir Set-samlingen en delete-metode for å slette en spesifikk verdi fra arrayet, deretter konvertere Set-samlingen til et array med spredningsoperatoren.

function deleteItem(list, val) {
    const set = new Set(list);
    set.delete(val);
    
    return [...set];
}

const letters = ['A', 'B', 'C', 'D', 'E'];
console.log(deleteItem(letters, 'C')); // ['A', 'B', 'D', 'E']

Svar #30

For en skam at du har et array av heltall, ikke et objekt hvor nøklene er strengversjoner av disse heltallene.

Jeg har sett gjennom mange av disse svarene, og de ser alle ut til å bruke "brute force" så langt jeg kan se. Jeg har ikke undersøkt hver enkelt, beklager hvis dette ikke er tilfelle. For et lite array er dette greit, men hva om du har tusenvis av heltall i det?

Korriger meg hvis jeg tar feil, men kan vi ikke anta at i et key => value-kart, av den typen som et JavaScript-objekt er, kan nøkkeloppslagsmekanismen antas å være høyt utviklet og optimalisert? (NB: hvis en super-ekspert forteller meg at dette ikke er tilfellet, kan jeg foreslå å bruke ECMAScript 6s Map-klasse i stedet, som definitivt vil være det).

Jeg foreslår bare at, under visse omstendigheter, kan den beste løsningen være å konvertere arrayet ditt til et objekt... problemet er selvfølgelig at du kan ha gjentakende heltallsverdier. Jeg foreslår å legge dem i beholdere som "verdi"-delen av key => value-oppføringene. (NB: hvis du er sikker på at du ikke har noen gjentakende array-elementer, kan dette være mye enklere: verdier "samme som" nøkler, og bare gå Object.values(...) for å få tilbake det endrede arrayet ditt).

Så du kunne gjøre:

const arr = [ 1, 2, 55, 3, 2, 4, 55 ];
const f =    function( acc, val, currIndex ){
    // We have not seen this value before: make a bucket... NB: although val's typeof is 'number',
    // there is seamless equivalence between the object key (always string)
    // and this variable val.
    ! ( val in acc ) ? acc[ val ] = []: 0;
    // Drop another array index in the bucket
    acc[ val ].push( currIndex );
    return acc;
}
const myIntsMapObj = arr.reduce( f, {});

console.log( myIntsMapObj );

Utdata :

Objekt [ <1 tom plass>, Array1, Array[2], Array1, Array1, <5 tomme plasser>, 46 til… ]

Det er da lett å slette alle tallene 55.

delete myIntsMapObj[ 55 ]; // Again, although keys are strings this works

Du trenger ikke å slette dem alle: indeksverdier blir lagt inn i bøttene sine i rekkefølge etter hvordan de dukker opp, så (for eksempel):

myIntsMapObj[ 55 ].shift(); // And
myIntsMapObj[ 55 ].pop();

vil slette den første og siste forekomsten henholdsvis. Du kan enkelt telle forekomstfrekvens, erstatte alle 55 med 3 ved å overføre innholdet fra en bøtte til en annen, osv.

Å hente en modifisert int-array fra ditt «bucket-objekt» er litt involvert, men ikke så mye: hver bøtte inneholder indeksen (i den opprinnelige arrayen) til verdien representert av (string) nøkkelen. Hver av disse bøtteverdiene er også unik (hver er den unike indeksverdien i den opprinnelige arrayen): så du gjør dem til nøkler i et nytt objekt, med den (ekte) heltallet fra «heltall-strengnøkkelen» som verdi... deretter sorterer du nøklene og går Object.values( ... ).

Dette høres veldig omfattende og tidkrevende ut... men åpenbart avhenger alt av omstendighetene og ønsket bruk. Min forståelse er at alle versjoner og kontekster av JavaScript bare opererer i én tråd, og tråden gir ikke «slipp», så det kan bli noen forferdelige køproblemer med en «brute force»-metode: forårsaket ikke så mye av indexOf-operasjonene, men av flere gjentatte slice/splice-operasjoner.

Tillegg Hvis du er sikker på at dette er for mye ingeniørarbeid for ditt brukstilfelle, er sikkert den enkleste «brute force»-tilnærmingen

const arr = [ 1, 2, 3, 66, 8, 2, 3, 2 ];
const newArray = arr.filter( number => number !== 3 );
console.log( newArray )

(Ja, andre svar har merket Array.prototype.filter...)

Relaterte artikler