J'ai le code suivant pour la boucle et lorsque j'utilise splice()
pour supprimer un élément, le message «secondes» n'est pas défini. Je pourrais vérifier si ce n'est pas défini, mais j'estime qu'il existe probablement un moyen plus élégant de le faire. Le désir est simplement de supprimer un élément et de continuer.
for (i = 0, len = Auction.auctions.length; i < len; i++) {
auction = Auction.auctions[i];
Auction.auctions[i]['seconds'] --;
if (auction.seconds < 0) {
Auction.auctions.splice(i, 1);
}
}
Le tableau est en cours de réindexation lorsque vous effectuez une .splice()
, ce qui signifie que vous ignorez un index lorsque celui-ci est supprimé et que votre .length
mis en cache est obsolète.
Pour résoudre ce problème, vous devez soit décrémenter i
après une .splice()
, soit simplement effectuer une itération inverse ...
var i = Auction.auctions.length
while (i--) {
...
if (...) {
Auction.auctions.splice(i, 1);
}
}
Ainsi, la réindexation n'affecte pas l'élément suivant de l'itération, car elle n'affecte que les éléments du point actuel à la fin du tableau et que l'élément suivant de l'itération est inférieur au point actuel.
C'est un problème assez commun. La solution consiste à effectuer une boucle en arrière:
for (var i = Auction.auctions.length - 1; i >= 0; i--) {
Auction.auctions[i].seconds--;
if (Auction.auctions[i].seconds < 0) {
Auction.auctions.splice(i, 1);
}
}
Peu importe si vous les sortez de la fin, car les indices seront préservés à mesure que vous reculerez.
Recalculez la longueur à chaque fois dans la boucle plutôt que juste au début, par exemple:
for (i = 0; i < Auction.auctions.length; i++) {
auction = Auction.auctions[i];
Auction.auctions[i]['seconds'] --;
if (auction.seconds < 0) {
Auction.auctions.splice(i, 1);
i--; //decrement
}
}
De cette façon, vous ne dépasserez pas les limites.
EDIT: ajout d'un décrément dans l'instruction if.
Bien que votre question porte sur la suppression d'éléments de du tableau itéré sur et non pas sur la suppression d'éléments (en plus d'un autre traitement) de manière efficace, je pense que vous devriez le réexaminer si la situation est similaire.
La complexité algorithmique de cette approche est O(n^2)
en tant que fonction d’épissage et la boucle for se répète sur le tableau (la fonction d’épissage décale tous les éléments du tableau dans le pire des cas). Au lieu de cela, vous pouvez simplement pousser les éléments requis dans le nouveau tableau, puis assigner ce tableau à la variable souhaitée (qui a simplement été itérée).
var newArray = [];
for (var i = 0, len = Auction.auctions.length; i < len; i++) {
auction = Auction.auctions[i];
auction.seconds--;
if (!auction.seconds < 0) {
newArray.Push(auction);
}
}
Auction.auctions = newArray;
Depuis ES2015, nous pouvons utiliser Array.prototype.filter
pour tout adapter sur une seule ligne:
Auction.auctions = Auction.auctions.filter(auction => --auction.seconds >= 0);
Auction.auction = Auction.auctions.filter(function(el) {
return --el["seconds"] > 0;
});
Voici un autre exemple d'utilisation correcte de l'épissure. Cet exemple est sur le point de supprimer "attribut" de "tableau".
for (var i = array.length; i--;) {
if (array[i] === 'attribute') {
array.splice(i, 1);
}
}
Une autre solution simple pour digérer une fois les éléments d'un tableau:
while(Auction.auctions.length){
// From first to last...
var auction = Auction.auctions.shift();
// From last to first...
var auction = Auction.auctions.pop();
// Do stuff with auction
}
Si vous utilisez ES6 +, pourquoi ne pas utiliser simplement la méthode Array.filter?
Auction.auctions = Auction.auctions.filter((auction) => {
auction['seconds'] --;
return (auction.seconds > 0)
})
Notez que la modification de l'élément de tableau lors de l'itération du filtre ne fonctionne que pour les objets et ne fonctionne pas pour le tableau de valeurs primitives.
A chaque personne qui a répondu à cette question très élémentaire avec du code ayant splice () dans une boucle dont le temps d'exécution est O (n2), ou qui a voté en faveur d'une telle réponse, au cours des sept années qui suivent la publication de cette question: vous devriez avoir honte .
Voici une solution de temps linéaire simple à ce problème de temps linéaire simple.
Lorsque j'exécute cet extrait, avec n = 1 million, chaque appel à filterInPlace () prend 0,013 à 0,016 seconde. Une solution quadratique (par exemple, la réponse acceptée) prendrait un million de fois plus ou moins.
// Remove from array every item such that !condition(item).
function filterInPlace(array, condition) {
var iOut = 0;
for (var i = 0; i < array.length; i++)
if (condition(array[i]))
array[iOut++] = array[i];
array.length = iOut;
}
// Try it out. A quadratic solution would take a very long time.
var n = 1*1000*1000;
console.log("constructing array...");
var Auction = {auctions: []};
for (var i = 0; i < n; ++i) {
Auction.auctions.Push({seconds:1});
Auction.auctions.Push({seconds:2});
Auction.auctions.Push({seconds:0});
}
console.log("array length should be "+(3*n)+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be "+(2*n)+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be "+n+": ", Auction.auctions.length)
filterInPlace(Auction.auctions, function(auction) {return --auction.seconds >= 0; })
console.log("array length should be 0: ", Auction.auctions.length)
Notez que cela modifie le tableau original en place plutôt que de créer un nouveau tableau; le faire en place de cette façon peut être avantageux, par ex. dans le cas où la matrice est le seul goulot d'étranglement en mémoire du programme; dans ce cas, vous ne voulez pas créer un autre tableau de la même taille, même temporairement.
Il y a déjà beaucoup de réponses merveilleuses sur ce fil. Cependant, je souhaitais partager mon expérience lorsque j'ai tenté de résoudre le problème "supprimer le nième élément d'un tableau" dans le contexte ES5.
Les tableaux JavaScript ont différentes méthodes pour ajouter/supprimer des éléments de début ou de fin. Ceux-ci sont:
arr.Push(ele) - To add element(s) at the end of the array
arr.unshift(ele) - To add element(s) at the beginning of the array
arr.pop() - To remove last element from the array
arr.shift() - To remove first element from the array
Essentiellement, aucune des méthodes ci-dessus ne peut être utilisée directement pour supprimer le nième élément du tableau.
Un fait à noter est que ceci est en contraste avec l'itérateur Java avec lequel il est possible de supprimer le nième élément d’une collection en itérant.
Cela nous laisse essentiellement avec une seule méthode de tableau Array.splice
pour supprimer le nième élément (vous pouvez également faire d'autres choses avec ces méthodes, mais dans le contexte de cette question, je me concentre sur la suppression d'éléments):
Array.splice(index,1) - removes the element at the index
Voici le code copié de la réponse originale (avec commentaires):
var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length
while (i--) //decrement counter else it would run into IndexOutBounds exception
{
if (arr[i] === "four" || arr[i] === "two") {
//splice modifies the original array
arr.splice(i, 1); //never runs into IndexOutBounds exception
console.log("Element removed. arr: ");
} else {
console.log("Element not removed. arr: ");
}
console.log(arr);
}
Une autre méthode remarquable est Array.slice
. Cependant, le type de retour de cette méthode est constitué des éléments supprimés. De plus, cela ne modifie pas le tableau d'origine. Extrait de code modifié comme suit:
var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length
while (i--) //decrement counter
{
if (arr[i] === "four" || arr[i] === "two") {
console.log("Element removed. arr: ");
console.log(arr.slice(i, i + 1));
console.log("Original array: ");
console.log(arr);
}
}
Ceci dit, nous pouvons toujours utiliser Array.slice
pour supprimer le nième élément de la manière suivante et, comme vous pouvez le constater, il y a beaucoup plus de code (donc inefficace).
var arr = ["one", "two", "three", "four"];
var i = arr.length; //initialize counter to array length
while (i--) //decrement counter
{
if (arr[i] === "four" || arr[i] === "two") {
console.log("Array after removal of ith element: ");
arr = arr.slice(0, i).concat(arr.slice(i + 1));
console.log(arr);
}
}
La méthode
Array.slice
est extrêmement importante à atteindre immuabilité en programmation fonctionnelle à la redux
for (i = 0, len = Auction.auctions.length; i < len; i++) {
auction = Auction.auctions[i];
Auction.auctions[i]['seconds'] --;
if (auction.seconds < 0) {
Auction.auctions.splice(i, 1);
i--;
len--;
}
}
Essayez de relayer un tableau dans newArray lors de la mise en boucle:
var auctions = Auction.auctions;
var auctionIndex;
var auction;
var newAuctions = [];
for (
auctionIndex = 0;
auctionIndex < Auction.auctions.length;
auctionIndex++) {
auction = auctions[auctionIndex];
if (auction.seconds >= 0) {
newAuctions.Push(
auction);
}
}
Auction.auctions = newAuctions;
Vous pouvez simplement regarder à travers et utiliser shift()