2015-01-15 3 views
1

У меня есть список, и я прокручиваю его, удаляя элементы в Списке, если есть совпадение. Я использую i = -1, если элемент в списке удален. Но это снова начинается с начала. Есть лучший способ сделать это?Лучше всего перебирать список <String> и удалять элементы

private List<String> populateList(List<String> listVar) { 
    List<String> list = new ArrayList<String>(); 
    list.add("2015-01-13 09:30:00"); 
    list.add("2015-01-13 06:22:12"); 
    list.add("2015-01-12 05:45:10"); 
    list.add("2015-01-12 01:52:40"); 
    list.add("2015-01-12 02:23:45"); 
    return list; 
} 

private void removeItems() { 
    List<String> list = new ArrayList<String>(); 
    list = populateList(list); 
    System.out.println("List before modification : "+list); 
    for (int i = 0; i < list.size(); i++) { 
     String dateNoTime = list.get(i).split(" ")[0]; 
     System.out.println(" Going over : "+list.get(i)); 
     if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
      System.out.println("  Removing : "+list.get(i)); 
      list.remove(i); 
      i = -1; //This is making the loop start from scratch. Is there a better way? 
     } 
    } 
    System.out.println("List after modification: "+list+"\n\n"); 
} 
+0

Я что-то упустил? почему вы не можете просто удалить часть 'i = -1'? – SOfanatic

+0

Должно быть исключение параллельной модификации !? Вместо этого используйте Итератор. –

+0

только петля в обратном направлении. (от конца до начала) – njzk2

ответ

5

в Java List<T> обеспечивает лучший способ удаления элементов из нее с помощью ListIterator<T>:

ListIterator<String> iter = list.listIterator(); 
while (iter.hasNext()) { 
    String s = iter.next(); 
    String dateNoTime = s.split(" ")[0]; 
    if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
     iter.remove(); 
    } 
} 
0

Использование итераторов.

Javadoc для итератора говорит следующее

итераторы позволяют вызывающей удалить элементы из базовой коллекции во время итерации с четко определенными семантики.

1

Вы можете использовать интерфейс итератора, который имеет удалить метод.

Iterator<String> iterator = list.iterator(); 
    while (iterator.hasNext()) 
    { 
     String next = iterator.next(); 
     String dateNoTime = next.split(" ")[0]; 

     if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
      System.out.println("  Removing : "+next); 
      iterator.remove(); 
     } 
    } 
0

Или вы можете использовать API guava для его достижения.

FluentIterable 
     .from(list) 
     .transform(new Function<String, String>(){ 
      @Override 
      public void apply(String input){ 
       return input.split(" ")[0]; 
      } 
     }).filter(new Predicate<String>(){ 
      @Override 
      public boolean apply(String input){ 
       return input.equalsIgnoreCase("2015-01-13"); 
      } 
     }).toList(); 
1

С Java-8, вы можете упростить все дело в:

List<String> filtered = list.stream().filter(item -> item.split(" ")[0] 
                 .equalsIgnoreCase("2015-01-13")) 
                 .collect(Collectors.toList()); 

Я думаю, что это самый короткий путь, чтобы удалить элементы из списка, проверяя их один за другим. (Я имею в виду «кратчайший» с точки зрения размера кода, а не сложности).

1

Когда вы используете индекс для итерации по списку, и вы удаляете элементы из списка, вам нужно быть осторожным в том, как вы обрабатываете индекс. (. Выполнение remove через итератор, как в @ ответ dasblinkenlight является лучше в этом случае, но есть и другие подобные ситуации, когда это не представляется возможным)

Предположим, вы только что удалили строку, которая сбрасывает i:

for (int i = 0; i < list.size(); i++) { 
    String dateNoTime = list.get(i).split(" ")[0]; 
    System.out.println(" Going over : "+list.get(i)); 
    if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
     System.out.println("  Removing : "+list.get(i)); 
     list.remove(i); 
     //i = -1; //This is making the loop start from scratch. Is there a better way? 
    } 
} 

Теперь, когда i==2, вы решили, что вам нужно удалить элемент. Когда вы это сделаете, элемент, который был элементом 3, затем становится элементом 2, а элемент, который был элементом 4, становится элементом 3 и т. Д.

Но, тогда вы возвращаетесь наверх и увеличиваете i. Это сейчас 3. В результате элемент, который был элемент 3, но теперь элемент 2, никогда не рассматривается вообще. Он пропускается.

Есть несколько способов справиться с этим.

Нужно убедиться, что i не увеличивается.Я видел хорошие программисты делают такие вещи, как это:

for (int i = 0; i < list.size(); i++) { 
    String dateNoTime = list.get(i).split(" ")[0]; 
    System.out.println(" Going over : "+list.get(i)); 
    if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
     System.out.println("  Removing : "+list.get(i)); 
     list.remove(i); 
     i--; // Move "i" backwards so that no elements are skipped 
    } 
} 

Лично я не люблю изменение индекса внутри for цикла, как это, так что я был бы счастлив с

int i = 0; 
while (i < list.size()) { 
    String dateNoTime = list.get(i).split(" ")[0]; 
    System.out.println(" Going over : "+list.get(i)); 
    if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
     System.out.println("  Removing : "+list.get(i)); 
     list.remove(i); 
    } else { 
     i++; 
    } 
} 

[Обратите внимание, что в оба случая, важно использовать list.size() в состоянии завершения и не сохранять исходное значение в переменной. . Размер списка изменится, и вы хотите использовать новый размер при проверке окончания]

Другое решение, которое может быть уместным в некоторых случаях идти назад по списку:

for (int i = list.size() - 1; i >= 0; i--) 
    String dateNoTime = list.get(i).split(" ")[0]; 
    System.out.println(" Going over : "+list.get(i)); 
    if(!dateNoTime.equalsIgnoreCase("2015-01-13")) { 
     System.out.println("  Removing : "+list.get(i)); 
     list.remove(i); 
    } 
} 

который Безразлично У меня проблема, когда элементы смещены.

+0

Ницца. Очень хорошее объяснение! Благодаря! –

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