Suppression d'éléments de tableau en JavaScript - Supprimer vs épisser


1334

Quelle est la différence entre l'utilisation de l' deleteopérateur sur l'élément de tableau et l'utilisation de la Array.spliceméthode ?

Par exemple:

myArray = ['a', 'b', 'c', 'd'];

delete myArray[1];
//  or
myArray.splice (1, 1);

Pourquoi même avoir la méthode d'épissage si je peux supprimer des éléments de tableau comme je le peux avec des objets?


3
Pour les .spliceboucles in, jetez un œil à cette question: Supprimer du tableau en javascript .
Rob W

6
@andynormancx Oui, mais cette réponse a été publiée le lendemain et a obtenu tellement plus de votes - je dirais que c'est mieux écrit, ça doit être ça.
Camilo Martin

@andynormancx - Il ne semble pas s'agir d'un doublon exact. La question que vous avez liée est essentiellement de savoir pourquoi la suppression d'un élément d'un tableau (le rendant ainsi clairsemé) ne réduira pas sa longueur. Cette question demande les différences entre deleteet Array.prototype.splice.
chharvey

@chharvey a accepté, mais surtout comment cette question a-t-elle pu être publiée il y a 9 ans! Ça me fait me sentir vieux d'être de retour ici en commentant
andynormancx

Réponses:


1693

deletesupprimera la propriété de l'objet, mais ne réindexera pas le tableau ni ne mettra à jour sa longueur. Cela donne l'impression qu'il n'est pas défini:

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

Notez qu'il est en fait pas ensemble à la valeur undefinedplutôt la propriété est retirée du tableau, ce qui en fait apparaître non défini. Les outils de développement Chrome rendent cette distinction claire en imprimant emptylors de la journalisation de la baie.

> myArray[0]
  undefined
> myArray
  [empty, "b", "c", "d"]

myArray.splice(start, deleteCount) supprime réellement l'élément, réindexe le tableau et modifie sa longueur.

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> myArray.splice(0, 2)
  ["a", "b"]
> myArray
  ["c", "d"]

74
En fait, delete ne retirez l'élément, mais ne réindexer pas le tableau ou mettre à jour sa longueur (qui est sous - entendu par l'ancien puisque la longueur est toujours le plus haut indice + 1).
Felix Kling

3
JSlint n'aime pas la delete myArray[0]syntaxe disant " Attendu un opérateur et vu à la place" supprimer ". " L'utilisation spliceest recommandée.
Eye

21
@Eye: En fait, JSLint se plaint simplement de l'absence d'un point-virgule sur la ligne précédente. Et vous ne pouvez pas vraiment recommander l'un sur l'autre, car ils font des choses complètement différentes…
Ry-

3
"Supprimer dans ce cas ne définira l'élément que comme indéfini:" Non, c'est carrément incorrect. Il y a une différence fondamentale entre delete myArray[0]et myArray[0] = undefined. Dans le premier cas, la propriété est entièrement supprimée de l'objet tableau. Dans le second cas, la propriété reste, avec la valeur undefined.
TJ Crowder

1
Pour info, les outils de développement Chrome affichent le mot clé emptyau lieu d' undefinedaméliorer la distinction entre un élément de tableau réellement supprimé (ou non initialisé) et un élément qui a la valeur réelle de undefined. Notez que lorsque je dis cela, je veux dire qu'il s'affiche uniquement sous la forme emptyet ne fait pas référence à une valeur réelle appelée empty(qui n'existe pas).
chharvey

340

Array.remove (), méthode

John Resig , créateur de jQuery a créé une Array.removeméthode très pratique que je l'utilise toujours dans mes projets.

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

et voici quelques exemples de la façon dont il pourrait être utilisé:

// Remove the second item from the array
array.remove(1);
// Remove the second-to-last item from the array
array.remove(-2);
// Remove the second and third items from the array
array.remove(1,2);
// Remove the last and second-to-last items from the array
array.remove(-2,-1);

Site Web de John


4
+1 Pour Array.remove (). Cependant, il n'est pas heureux de recevoir des arguments de chaîne (contrairement à la plupart des méthodes de tableau, par exemple [1,2,3].slice('1'); // =[2,3]), il est donc plus sûr de le changer envar rest = this.slice(parseInt(to || from) + 1 || this.length);
Richard Inglis

1
@tomwrong, il n'y a pas de threads en javascript, et la fonction s'exécute this.push.apply(this, rest), puis renvoie la valeur qu'elle a renvoyée
billy

59
Cela ne répond pas du tout à la question.
Ry-

16
Pourquoi ne pas simplement utiliser splice ()? Le nom de cette fonction, les noms des paramètres et les résultats ne sont pas évidents. Ma recommandation est de simplement utiliser l'épissure (index, longueur) - (voir la réponse d'Andy Hume)
auco

3
La fonction fournie ci-dessus fonctionne comme expliqué, mais elle crée des effets secondaires indésirables lors de l'itération à travers le tableau avec le for(var i in array)cycle. Je l'ai supprimé et j'ai utilisé l'épissure à la place.
alexykot

104

Étant donné que la suppression supprime uniquement l'objet de l'élément du tableau, la longueur du tableau ne changera pas. Splice supprime l'objet et raccourcit le tableau.

Le code suivant affichera "a", "b", "non défini", "d"

myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

Alors que cela affichera "a", "b", "d"

myArray = ['a', 'b', 'c', 'd']; myArray.splice(2,1);

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

11
excellent exemple, sauf l'ambiguïté dans le deuxième exemple en utilisant 1,1 - le premier 1 fait référence à l'index dans le tableau pour démarrer l'épissure, le second 1 est le nombre d'éléments à supprimer. Donc, pour supprimer «c» du tableau d'origine, utilisezmyArray.splice(2,1)
iancoleman

68

Je suis tombé sur cette question en essayant de comprendre comment supprimer chaque occurrence d'un élément d'un tableau. Voici une comparaison de spliceet deletepour supprimer tous les éléments 'c'du itemstableau.

var items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  items.splice(items.indexOf('c'), 1);
}

console.log(items); // ["a", "b", "d", "a", "b", "d"]

items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  delete items[items.indexOf('c')];
}

console.log(items); // ["a", "b", undefined, "d", "a", "b", undefined, "d"]


10

splice fonctionnera avec des indices numériques.

alors qu'il deletepeut être utilisé contre d'autres types d'indices.

exemple:

delete myArray['text1'];

9
Quand vous dites «tout autre type d'indices», vous ne parlez plus de tableaux, mais plutôt d'objets, c'est ce que l'OP demande.
Yi Jiang

2
@YiJiang: Les tableaux sont des objets. Les indices sont des propriétés. Il n'y a pas de différence.
Bergi

9

Il convient également de mentionner que l'épissure ne fonctionne que sur les tableaux. (Les propriétés des objets ne peuvent pas être utilisées pour suivre un ordre cohérent.)

Pour supprimer la paire clé-valeur d'un objet, supprimer est en fait ce que vous voulez:

delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.

delete ne réorganise pas les clés du tableau, donc: var arr = [1,2,3,4,5]; supprimer arr [3]; for (var i = 0; i <= arr.length; i ++) console.log (arr [i]); présentera des résultats inattendus.
Kristian Williams

C'est vrai. Donc, à moins que vous ne vouliez laisser un élément non défini à cet emplacement, N'UTILISEZ PAS la suppression sur les clés d'un tableau! J'ai initialement ajouté ce commentaire pour inclure une référence à l'utilisation correcte de la suppression.
jtrick

mais pourquoi supprimer donnera un résultat inattendu ??
Alex

9

supprimer l'épissure Vs

lorsque vous supprimez un élément d'un tableau

var arr = [1,2,3,4]; delete arr[2]; //result [1, 2, 3:, 4]
console.log(arr)

quand vous épissez

var arr = [1,2,3,4]; arr.splice(1,1); //result [1, 3, 4]
console.log(arr);

en cas de suppression l' élément est supprimé mais le index reste vide

tandis qu'en cas d' épissage, l' élément est supprimé et l' indice des éléments de repos est réduit en conséquence


8

Comme indiqué à plusieurs reprises ci-dessus, l'utilisation splice()semble être un ajustement parfait. Documentation chez Mozilla:

La splice()méthode modifie le contenu d'un tableau en supprimant les éléments existants et / ou en ajoutant de nouveaux éléments.

var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

myFish.splice(2, 0, 'drum'); 
// myFish is ["angel", "clown", "drum", "mandarin", "sturgeon"]

myFish.splice(2, 1); 
// myFish is ["angel", "clown", "mandarin", "sturgeon"]

Syntaxe

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

Paramètres

début

Index auquel commencer à changer le tableau. S'il est supérieur à la longueur du tableau, l'index de départ réel sera défini sur la longueur du tableau. Si négatif, commencera autant d'éléments à partir de la fin.

deleteCount

Un entier indiquant le nombre d'anciens éléments de tableau à supprimer. Si deleteCount vaut 0, aucun élément n'est supprimé. Dans ce cas, vous devez spécifier au moins un nouvel élément. Si deleteCount est supérieur au nombre d'éléments restants dans le tableau à partir du début, tous les éléments jusqu'à la fin du tableau seront supprimés.

Si deleteCount est omis, deleteCount sera égal à (arr.length - start).

item1, item2, ...

Les éléments à ajouter au tableau, en commençant à l'index de départ. Si vous ne spécifiez aucun élément, splice()ne supprimera que les éléments du tableau.

Valeur de retour

Un tableau contenant les éléments supprimés. Si un seul élément est supprimé, un tableau d'un élément est renvoyé. Si aucun élément n'est supprimé, un tableau vide est renvoyé.

[...]


@downvoter: pourquoi le downvote? tiens à expliquer, ou non?
serv-inc

7

delete agit comme une situation non réelle, il supprime simplement l'élément, mais la longueur du tableau reste la même:

exemple du terminal de noeud:

> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]

Voici une fonction pour supprimer un élément d'un tableau par index, en utilisant slice () , il prend l'arr comme premier argument et l'index du membre que vous voulez supprimer comme deuxième argument. Comme vous pouvez le voir, il supprime en fait le membre du tableau et réduira la longueur du tableau de 1

function(arr,arrIndex){
    return arr.slice(0,arrIndex).concat(arr.slice(arrIndex + 1));
}

Ce que fait la fonction ci-dessus, c'est de prendre tous les membres jusqu'à l'index et tous les membres après l'index, de les concaténer ensemble et de retourner le résultat.

Voici un exemple utilisant la fonction ci-dessus comme module de nœud, voir le terminal sera utile:

> var arr = ["a","b","c","d"]
> arr
[ 'a', 'b', 'c', 'd' ]
> arr.length
4 
> var arrayRemoveIndex = require("./lib/array_remove_index");
> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))
> newArray
[ 'a', 'b', 'd' ] // c ya later
> newArray.length
3

veuillez noter que cela ne fonctionnera pas avec un seul tableau contenant des dupes, car indexOf ("c") obtiendra simplement la première occurrence, et ne fera qu'épisser et supprimer le premier "c" qu'il trouve.


6

Si vous souhaitez parcourir un grand tableau et supprimer des éléments de manière sélective, il serait coûteux d'appeler splice () pour chaque suppression car splice () devrait réindexer les éléments suivants à chaque fois. Étant donné que les tableaux sont associatifs en Javascript, il serait plus efficace de supprimer les éléments individuels, puis de réindexer le tableau par la suite.

Vous pouvez le faire en créant un nouveau tableau. par exemple

function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

Mais je ne pense pas que vous puissiez modifier les valeurs de clé dans le tableau d'origine, ce qui serait plus efficace - il semblerait que vous deviez créer un nouveau tableau.

Notez que vous n'avez pas besoin de vérifier les entrées "non définies" car elles n'existent pas réellement et la boucle for ne les renvoie pas. C'est un artefact de l'impression en réseau qui les affiche comme indéfinis. Ils ne semblent pas exister dans la mémoire.

Ce serait bien si vous pouviez utiliser quelque chose comme slice () qui serait plus rapide, mais il ne se réindexerait pas. Quelqu'un connaît une meilleure façon?


En fait, vous pouvez probablement le faire en place comme suit, ce qui est probablement plus efficace, en termes de performances:

reindexArray : function( array )
{
    var index = 0;                          // The index where the element should be
    for( var key in array )                 // Iterate the array
    {
        if( parseInt( key ) !== index )     // If the element is out of sequence
        {
            array[index] = array[key];      // Move it to the correct, earlier position in the array
            ++index;                        // Update the index
        }
    }

    array.splice( index );  // Remove any remaining elements (These will be duplicates of earlier items)
},

Je crois que l'index ++; doit se produire en dehors du «si». Making edit
mishal153

6

vous pouvez utiliser quelque chose comme ça

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


c'est plus intuitif que slicesi vous venez d'un milieu fonctionnel (probablement moins efficace, cependant).
jethro

3

Pourquoi ne pas simplement filtrer? Je pense que c'est la façon la plus claire de considérer les tableaux en js.

myArray = myArray.filter(function(item){
    return item.anProperty != whoShouldBeDeleted
});

Qu'en est-il d'un tableau contenant des centaines (sinon des milliers) d'enregistrements dont seuls 3 doivent être supprimés?
Joel Hernandez

bon point. J'utilise cette méthode pour les tableaux clairsemés dont la longueur ne dépasse pas 200 ou 300 et fonctionne très bien. Cependant, je pense que les bibliothèques comme le soulignement devraient être préférées si vous devez gérer des tableaux plus grands.
Asqan

1
Cependant, cela me semble beaucoup plus agréable que moi deleteou slice.
Juneyoung Oh

3

La différence peut être vue en enregistrant la longueur de chaque tableau après l'application de l' deleteopérateur et de la splice()méthode. Par exemple:

supprimer l'opérateur

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];

console.log(trees); // ["redwood", "bay", "cedar", empty, "maple"]
console.log(trees.length); // 5

L' deleteopérateur supprime l'élément du tableau, mais l '"espace réservé" de l'élément existe toujours.oaka été supprimé mais il prend toujours de la place dans le tableau. Pour cette raison, la longueur du tableau reste 5.

méthode splice ()

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);

console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4

La splice()méthode supprime complètement la valeur cible et "l'espace réservé" également. oaka été supprimé ainsi que l'espace qu'il occupait auparavant dans le tableau. La longueur du tableau est désormais de 4.


2
function remove_array_value(array, value) {
    var index = array.indexOf(value);
    if (index >= 0) {
        array.splice(index, 1);
        reindex_array(array);
    }
}
function reindex_array(array) {
   var result = [];
    for (var key in array) {
        result.push(array[key]);
    }
    return result;
}

exemple:

var example_arr = ['apple', 'banana', 'lemon'];   // length = 3
remove_array_value(example_arr, 'banana');

la banane est supprimée et la longueur du tableau = 2


2

Ce sont des choses différentes qui ont des objectifs différents.

spliceest spécifique au tableau et, lorsqu'il est utilisé pour la suppression, supprime les entrées du tableau et déplace toutes les entrées précédentes vers le haut pour combler l'écart. (Il peut également être utilisé pour insérer des entrées, ou les deux en même temps.) spliceChangera lengthle tableau (en supposant que ce n'est pas un appel sans opération:) theArray.splice(x, 0).

deleten'est pas spécifique à un tableau; il est conçu pour être utilisé sur des objets: il supprime une propriété (paire clé / valeur) de l'objet sur lequel vous l'utilisez. Cela ne s'applique qu'aux tableaux car les tableaux standard (par exemple, non typés) en JavaScript ne sont pas du tout des tableaux *, ce sont des objets avec une gestion spéciale pour certaines propriétés, comme ceux dont les noms sont des "index de tableau" (qui sont définis comme des noms de chaîne "... dont la valeur numérique iest dans la plage +0 ≤ i < 2^32-1") et length. Lorsque vous utilisez deletepour supprimer une entrée de tableau, il ne fait que supprimer l'entrée; il ne déplace pas les autres entrées qui le suivent pour combler l'écart, et donc le tableau devient "clairsemé" (certaines entrées sont complètement manquantes). Cela n'a aucun effet sur length.

Quelques-unes des réponses actuelles à cette question indiquent à tort que l'utilisation de delete"définit l'entrée undefined". Ce n'est pas correct. Il supprime entièrement l'entrée (propriété), laissant un espace.

Utilisons du code pour illustrer les différences:

console.log("Using `splice`:");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a.splice(0, 1);
console.log(a.length);            // 4
console.log(a[0]);                // "b"

console.log("Using `delete`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
delete a[0];
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // false
console.log(a.hasOwnProperty(0)); // false

console.log("Setting to `undefined`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a[0] = undefined;
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // true
console.log(a.hasOwnProperty(0)); // true


* (c'est un article sur mon petit blog anémique)


2

Actuellement, il existe deux façons de procéder

  1. en utilisant splice ()

    arrayObject.splice(index, 1);

  2. en utilisant supprimer

    delete arrayObject[index];

Mais je suggère toujours d'utiliser l'épissure pour les objets de tableau et de supprimer pour les attributs d'objet car la suppression ne met pas à jour la longueur du tableau.


1

OK, imaginez que nous avons ce tableau ci-dessous:

const arr = [1, 2, 3, 4, 5];

Supprimons d'abord:

delete arr[1];

et voici le résultat:

[1, empty, 3, 4, 5];

vide!et allons-y:

arr[1]; //undefined

Cela signifie donc juste la valeur supprimée et c'est pas définie maintenant, donc la longueur est la même, elle reviendra également vraie ...

Réinitialisons notre tableau et faisons-le avec une épissure cette fois:

arr.splice(1, 1);

et voici le résultat cette fois:

[1, 3, 4, 5];

Comme vous le voyez, la longueur du tableau a changé et arr[1] est désormais de 3 ...

Cela retournera également l'élément supprimé dans un tableau qui est [3]dans ce cas ...


1

D'autres ont déjà correctement comparé deleteavecsplice .

Une autre comparaison intéressante est deletepar rapport à undefined: un élément de tableau supprimé utilise moins de mémoire que celui qui vient d'être défini sur undefined;

Par exemple, ce code ne se terminera pas:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Il produit cette erreur:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Donc, comme vous pouvez le voir, cela undefinedprend en fait de la mémoire.

Cependant, si vous avez également deletel'élément ary (au lieu de le définir uniquement undefined), le code se terminera lentement:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Ce sont des exemples extrêmes, mais ils soulignent deleteque je n'ai vu personne mentionner nulle part.


1

Si vous avez un petit tableau, vous pouvez utiliser filter:

myArray = ['a', 'b', 'c', 'd'];
myArray = myArray.filter(x => x !== 'b');

0

Le moyen le plus simple est probablement

var myArray = ['a', 'b', 'c', 'd'];
delete myArray[1]; // ['a', undefined, 'c', 'd']. Then use lodash compact method to remove false, null, 0, "", undefined and NaN
myArray = _.compact(myArray); ['a', 'c', 'd'];

J'espère que cela t'aides. Référence: https://lodash.com/docs#compact


1
Si quelqu'un trébuche sur cette question compact... pas besoin de lodash. EssayezmyArray.filter(function(n){return n;})
dat

0

Pour ceux qui veulent utiliser Lodash peuvent utiliser: myArray = _.without(myArray, itemToRemove)

Ou comme j'utilise dans Angular2

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...

0

delete : delete supprimera la propriété de l'objet, mais ne réindexera pas le tableau ni ne mettra à jour sa longueur. Cela donne l'impression qu'il n'est pas défini:

splice : supprime réellement l'élément, réindexe le tableau et modifie sa longueur.

Supprimer l'élément du dernier

arrName.pop();

Supprimer l'élément du premier

arrName.shift();

Supprimer du milieu

arrName.splice(starting index,number of element you wnt to delete);

Ex: arrName.splice(1,1);

Supprimer un élément du dernier

arrName.splice(-1);

Supprimer en utilisant le numéro d'index du tableau

 delete arrName[1];

0

Si l'élément à supprimer se trouve au milieu (disons que nous voulons supprimer «c», dont son index est 1), vous pouvez utiliser:

var arr = ['a','b','c'];
var indexToDelete = 1;
var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))

0

IndexOfaccepte également un type de référence. Supposons le scénario suivant:

var arr = [{item: 1}, {item: 2}, {item: 3}];
var found = find(2, 3); //pseudo code: will return [{item: 2}, {item:3}]
var l = found.length;

while(l--) {
   var index = arr.indexOf(found[l])
      arr.splice(index, 1);
   }
   
console.log(arr.length); //1

Différemment:

var item2 = findUnique(2); //will return {item: 2}
var l = arr.length;
var found = false;
  while(!found && l--) {
  found = arr[l] === item2;
}

console.log(l, arr[l]);// l is index, arr[l] is the item you look for

-1
function deleteFromArray(array, indexToDelete){
  var remain = new Array();
  for(var i in array){
    if(array[i] == indexToDelete){
      continue;
    }
    remain.push(array[i]);
  }
  return remain;
}

myArray = ['a', 'b', 'c', 'd'];
deleteFromArray(myArray , 0);

// résultat: myArray = ['b', 'c', 'd'];


@ChrisDennis pourquoi? (pas de sarcasme ni de malveillance, c'est une question sincère)
Chris Bier

Outre le fait que cette réponse ne répond pas à la question du PO
Chris Bier
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.