2013-05-03 2 views
47

У меня есть массив элементов и вам нужно удалить некоторые из них. Проблема в том, что JavaScript, похоже, не имеет для каждого цикла, и если я использую цикл for, я сталкиваюсь с проблемами с ним, в основном, пытаясь проверить элементы за пределами массива или отсутствующие элементы в массиве, потому что индексы меняются , Позвольте мне показать вам, что я имею в виду:Как перебрать массив и удалить элементы в JavaScript

var elements = [1, 5, 5, 3, 5, 2, 4]; 
for(var i = 0; i < elements.length; i++){ 
    if(elements[i] == 5){ 
     elements.splice(i, 1); 
    } 
} 

Проблема заключается в том, что, когда элементы [1] удаляют элементы [2] становится элементы [1]. Поэтому первая проблема заключается в том, что некоторые элементы никогда не рассматриваются. Другая проблема заключается в том, что .length изменяется, и если я жестко кодирую границы, тогда я могу попытаться изучить элементы за пределами массива. Так что лучший способ сделать это невероятно просто?

+1

'elements.splice (i--, 1);' –

+0

мне не нравится "-" или "++" синтаксис но полезный совет при запуске с начала массива +1 – Xotic750

+0

См. также: [Цитирование и удаление элементов, без прерывания цикла] (http://stackoverflow.com/q/9882284/1591669) – unor

ответ

125

Начинайте с вершины!

var elements = [1, 5, 5, 3, 5, 2, 4]; 
for(var i = elements.length -1; i >= 0 ; i--){ 
    if(elements[i] == 5){ 
     elements.splice(i, 1); 
    } 
} 
+1

+1 для звезда начиная с конца, чтобы избежать пропусков элементов из-за изменения длины, указанной в OP. – Xotic750

+9

'for (var i = elements.length; i -;)', вероятно, более распространенный способ его записи. –

+0

@Dagg Nabbit, одно примечание с этой стенографией заключается в том, что оно будет вызывать ошибки в jslint, если вы должны использовать такой инструмент для анализа статического кода (и, конечно, «-»). – Xotic750

21

Вы можете использовать filter метод здесь:

var elements = [1, 5, 5, 3, 5, 2, 4].filter(function(a){return a !== 5;}); 
//=> elements now [1,3,2,4] 

Или, если вы не хотите трогать elements:

var elementsfiltered 
    ,elements = [1, 5, 5, 3, 5, 2, 4] 
       .filter(function(a){if (a!==5) this.push(a); return true;}, 
         elementsfiltered = []); 
    //=> elementsfiltered = [1,3,2,4], elements = [1, 5, 5, 3, 5, 2, 4] 

Посмотреть MDN documentation для filter

Или вы может расширять Array.prototype

Array.prototype.remove = Array.prototype.remove || function(val){ 
    var i = this.length; 
    while(i--){ 
     if (this[i] === val){ 
      this.splice(i,1); 
     } 
    } 
}; 
var elements = [1, 5, 5, 3, 5, 2, 4]; 
elements.remove(5); 
//=> elements now [1,3,2,4] 
+1

При создании нового массива, который делает фильтр, не является плохим предложением в качестве решения, OP действительно спрашивает об удалении элементов inline, и было бы лучше всего привести пример этого. – Xotic750

+1

Похоже на ненужный отход от исходного кода. OP может сохранить свой существующий код, уменьшив «i» после сращивания. –

+0

лично я чувствую, что фильтр более безопасен как декрементирующий i, может привести к красным случаям, как если бы были нулевые элементы и т. Д. –

0

Это пример использования Array.indexOf, while и Array.splice для удаления элементов инлайн.

var elements = [1, 5, 5, 3, 5, 2, 4]; 
var remove = 5; 
var index = elements.indexOf(remove); 

while (index !== -1) { 
    elements.splice(index, 1); 
    index = elements.indexOf(remove); 
} 

console.log(elements); 

На jsfiddle

+0

downvoted для неэффективного алгоритма O (n^2) – Alnitak

+0

Я никогда не делал никаких претензий относительно эффективности, и вопрос не касался того, что , но как вы можете иметь дело с изменяющейся длиной массива при выполнении удаления встроенного элемента. Вот jsPerf, чтобы вы могли дать свою эффективную версию в качестве ответа и сравнить ее с другими опубликованными ответами. http://jsperf.com/soq-iterate-over-an-array-and-remove – Xotic750

+0

Канонический метод обращения с изменяющейся длиной массива должен начинаться с конца массива и работать в обратном направлении. В качестве альтернативы можно работать вперед _ из текущей позиции_ и не увеличивать, если вы удалили текущий элемент. Вместо этого ваш метод _ начинается с нулевого элемента_ каждый раз, когда совпадение найдено, тем самым неоднократно переходя через одни и те же элементы. Это очень плохой алгоритм и никогда не должен использоваться. – Alnitak

1

Использование Array.shift():

var array = [1, 2, 3, 'a', 'b', 'c']; 
while (array.length > 0) { 
    console.log(array.shift()); 
} 

Edit: Возможно, не устраивает спецификации. Я неправильно вопрос (только удалить определенные элементы) и был слишком нетерпелив вместо того, чтобы добавить метод, который еще не был упомянут ...

+1

Как вы говорите в своем редактировании, это фактически не отвечает на вопрос, однако он отвечает на вопрос, который я пытался найти. Спасибо. – spikyjt

1

Вы могли бы просто декремент i всякий раз, когда вы удалите элемент.

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

 
var l = elements.length; 
 
for(var i = 0; i < l; i++){ 
 
    if(elements[i] == 5){ 
 
     elements.splice(i, 1); 
 
     i--; 
 
    } 
 
} 
 

 
console.log(elements);

2

var elements = [1, 5, 5, 3, 5, 2, 4];  
 
var i = elements.length; 
 
while (i--) { 
 
    if (elements[i] == 5) { 
 
     elements.splice(i, 1); 
 
    } 
 
} 
 
console.log(elements);

+1

С точки зрения читаемости кода этот ответ прекрасен –

Смежные вопросы