javascript - riot - Bucle para eliminar un elemento de la matriz con varias apariciones
riot js español (10)
Crear un conjunto dado una matriz, la matriz original no está modificada
var array=["hello","hello","world",1,"world"];
function removeDups(items) {
var i,
setObj = {},
setArray = [];
for (i = 0; i < items.length; i += 1) {
if (!setObj.hasOwnProperty(items[i])) {
setArray.push(items[i]);
setObj[items[i]] = true;
}
}
return setArray;
}
console.log(removeDups(array)); // ["hello", "world", 1]
Quiero eliminar un elemento de una matriz con varias apariciones con una función.
var array=["hello","hello","world",1,"world"];
function removeItem(item){
for(i in array){
if(array[i]==item) array.splice(i,1);
}
}
removeItem("world");
//Return hello,hello,1
removeItem("hello");
//Return hello,world,1,world
Este bucle no elimina el elemento cuando se repite dos veces en secuencia, solo elimina uno de ellos.
¿Por qué?
Debo decir que mi enfoque no hace uso de la función de splice
y que también necesita otra matriz para esta solución.
En primer lugar, supongo que su forma de hacer un loop de una matriz no es la correcta. Usted está utilizando for in
bucles que son para objetos, no matrices. Es mejor que uses $.each
en caso de que estés usando jQuery o Array.prototype.forEach
si estás usando vanila Javascript.
En segundo lugar, ¿por qué no crear una nueva matriz vacía, recorrerla en bucle y agregar solo los elementos únicos a la nueva matriz, así:
PRIMER ENFOQUE (jQuery) :
var newArray = [];
$.each(array, function(i, element) {
if ($.inArray(element, newArray) === -1) {
newArray.push(region);
}
});
SEGUNDO ENFOQUE (Vanila Javascript) :
var newArray = [];
array.forEach(function(i, element) {
if (newArray.indexOf(element) === -1) {
newArray.push(region);
}
});
Esto se debe a que for
-loop va al siguiente elemento después de que se elimina la aparición, por lo que se omite el elemento directamente después de ese elemento.
Por ejemplo, supongamos que el item1
debe eliminarse en esta matriz (tenga en cuenta que <-
es el índice del bucle):
item1 (<-), item2, item3
después de eliminar:
item2 (<-), item3
y después de que se actualice el índice (como se terminó el ciclo)
item2, item3 (<-)
¡Así que puedes ver que item2
se omite y por lo tanto no se marca!
Por lo tanto, tendría que compensar esto reduciendo manualmente el índice en 1, como se muestra aquí:
function removeItem(item){
for(var i = 0; i < array.length; i++){
if(array[i]==item) {
array.splice(i,1);
i--; // Prevent skipping an item
}
}
}
En lugar de usar esto for
-loop, puedes usar métodos más "modernos" para filter los elementos no deseados como se muestra en la otra respuesta de Benjamin .
Intente ejecutar su código "manualmente": los "hola" se están siguiendo. elimina el primero, su matriz se reduce en un elemento y ahora el índice que sigue sigue al siguiente elemento.
eliminar "hola" "Iniciar bucle. i = 0, array = [" hola "," hola "," world ", 1," world "] i está apuntando a" hola "eliminar el primer elemento, i = 0 array = [ "hello", "world", 1, "world"] siguiente bucle, i = 1, array = ["hello", "world", 1, "world"]. El segundo "hello" no se eliminará.
Veamos "mundo" = i = 2, está apuntando a "mundo" (eliminar). en el siguiente bucle, la matriz es: ["hola", "hola", 1, "mundo"] ei = 3. Aquí fue el segundo "mundo".
que deseas que pase ¿Quieres eliminar todas las instancias del elemento? o solo el primero? para el primer caso, la eliminación debe estar en
while (array[i] == item) array.splice(i,1);
para el segundo caso - devuélvalo tan pronto como haya retirado el artículo.
Necesitaba una ligera variación de esto, la capacidad de eliminar ''n'' ocurrencias de un elemento de una matriz, así que modifiqué la respuesta de @ Veger como:
function removeArrayItemNTimes(arr,toRemove,times){
times = times || 10;
for(var i = 0; i < arr.length; i++){
if(arr[i]==toRemove) {
arr.splice(i,1);
i--; // Prevent skipping an item
times--;
if (times<=0) break;
}
}
return arr;
}
Ninguna de estas respuestas es muy óptima. La respuesta aceptada con el filtro dará como resultado una nueva instancia de una matriz. La respuesta con el segundo mayor número de votos, el bucle for que da un paso atrás en cada empalme, es innecesariamente compleja.
Si desea realizar el enfoque de bucle for, solo cuente hacia atrás hasta 0.
for (var i = array.length - 0; i >= 0; i--) {
if (array[i] === item) {
array.splice(i, 1);
}
}
Sin embargo, he usado un método sorprendentemente rápido con un bucle while e indexOf:
var itemIndex = 0;
while ((itemIndex = valuesArray.indexOf(findItem, itemIndex)) > -1) {
valuesArray.splice(itemIndex, 1);
}
Lo que hace que este método no sea repetitivo es que después de cualquier eliminación, la siguiente búsqueda comenzará en el índice del siguiente elemento después del elemento eliminado. Esto se debe a que puede pasar un índice de inicio a indexOf
como segundo parámetro.
En un caso de prueba jsPerf que compara los dos métodos anteriores y el método de filtro aceptado, el indexOf
finalizó rutinariamente primero en Firefox y Chrome, y fue segundo en IE. El método de filter
siempre fue más lento por un amplio margen.
Conclusión: cualquiera de los dos modos inverso para bucle son un tiempo con indexOf, actualmente son los mejores métodos que puedo encontrar para eliminar varias instancias del mismo elemento de una matriz. Usar el filtro crea una nueva matriz y es más lento, así que evitaría eso.
Puede usar el siguiente fragmento de código para eliminar varias apariciones de value val
en array arr
.
while(arr.indexOf(val)!=-1){
arr.splice(arr.indexOf(val), 1);
}
Puede usar loadash o guión bajo js en este caso, si arr es una matriz, puede eliminar duplicados de la siguiente manera:
var arr = [2,3,4,4,5,5];
arr = _.uniq(arr);
Tiene una función incorporada llamada filter
que filtra una matriz según un predicado (una condición).
No altera la matriz original, pero devuelve una nueva filtrada.
var array=["hello","hello","world",1,"world"];
var filtered = array.filter(function(element) {
return element !== "hello";
}); // filtered contains no occurrences of hello
Puedes extraerlo a una función:
function without(array, what){
return array.filter(function(element){
return element !== what;
});
}
Sin embargo, el filtro original parece bastante expresivo.
Su función original tiene algunos problemas:
- Se itera la matriz utilizando un bucle
for... in
que no tiene garantía en el orden de iteración. Además, no lo use para iterar a través de matrices , prefiera un bucle normalfor...
o un.forEach
- Está iterando una matriz con un error de apagado por lo que está saltando en el siguiente elemento, ya que ambos están eliminando el elemento y avanzando la matriz.
Un enfoque alternativo sería ordenar la matriz y luego jugar con los índices de los valores.
function(arr) {
var sortedArray = arr.sort();
//In case of numbers, you can use arr.sort(function(a,b) {return a - b;})
for (var i = 0; sortedArray.length; i++) {
if (sortedArray.indexOf(sortedArray[i]) === sortedArray.lastIndexOf(sortedArray[i]))
continue;
else
sortedArray.splice(sortedArray.indexOf(sortedArray[i]), (sortedArray.lastIndexOf(sortedArray[i]) - sortedArray.indexOf(sortedArray[i])));
}
}