0

У меня есть два списка в гнезде для цикла. Когда я сопоставлял элемент внутри, я хочу удалить его, чтобы производительность работала.Как удалить элемент в списке?

List<String[]> brandList = readCsvFile("/tmp/brand.csv"); 
List<String[]> themeList = readCsvFile("/tmp/theme.csv"); 

for (String[] brand : brandList) { 
    for (String[] theme : themeList) { 
     if (brand[0].equals(theme[0])) { 
      themeList.remove(theme); 
     } 
    } 
} 

У меня ошибка java.util.ConcurrentModificationException. Если я изменил CopyOnWriteArrayList, ошибка, как показано ниже:

CopyOnWriteArrayList<String[]> themeList = (CopyOnWriteArrayList<String[]>)readCsvFile("/tmp/theme.csv"); 

java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.concurrent.CopyOnWriteArrayList 

Теперь, как я могу сделать? опустить удалить? или в любом случае?

Я думаю, что это то, что мне нужно:

List<String[]> brandList = readCsvFile("/tmp/brand.csv"); 
List<String[]> themeList = readCsvFile("/tmp/theme.csv"); 

for (String[] brand : brandList) { 
    List<String[]> toRemove = new ArrayList<String[]>(); 

    for (String[] theme : themeList) { 
     if (brand[0].equals(theme[0])) { 
      toRemove.add(theme); 
     } 
    } 

    for (String[] theme : toRemove) { 
     themeList.removeAll(theme); 
    } 
} 

ответ

3

Вы не можете удалять элементы из Collection в то время как вы итерацию над ней, что это был foreach цикл в Java по существу делает. Вы должны создать новый List<String[]> и собрать все элементы, которые вы хотите удалить, а затем удалить их после того, как вы итерацию через Collection:

List<String[]> brandList = readCsvFile("/tmp/brand.csv"); 
List<String[]> themeList = readCsvFile("/tmp/theme.csv"); 
List<String[]> toRemove = new ArrayList<String[]>(); 

for (String[] brand : brandList) { 
    for (String[] theme : themeList) { 
     if (brand[0].equals(theme[0])) { 
      toRemove.add(theme); 
     } 
    } 
} 
themeList.removeAll(theme); 
+0

Ваш код не то, что я хочу, я могу поместить themeList.removeAll (toRemove); внутри внешней петли? – mikezang

+0

Более эффективно размещать это вне петель, так как выполняется только одна операция удаления для всех элементов, которые необходимо удалить. Это, конечно, возможно, но из этого фрагмента кода я не вижу, где лежит семантическая разница. – chucktator

+0

Ваш ответ дал мне идею, спасибо! – mikezang

0

Это не так красиво, но вы можете сделать это с помощью итератора:

List<String[]> brandList = readCsvFile("/tmp/brand.csv"); 
List<String[]> themeList = readCsvFile("/tmp/theme.csv"); 

for (String[] brand : brandList) { 
    Iterator<String[]> themeIterator = themeList.iterator(); 
    while (themeIterator.hasNext()) { 
     String[] theme = themeIterator.next(); 
     if (brand[0].equals(theme[0])) { 
      themeIterator.remove(); 
      // If you are sure there is only one theme per brand, add a break here 
      // break; 
     } 
    } 
} 

в зависимости от конкретного типа List<>themeList есть (список массива, связанный список и т.д.), это может или не может быть быстрее, чем вариант копирования.

+0

В одном бренде есть несколько тем! – mikezang

+0

Вот почему перерыв прокомментирован :) –

+0

Этот код также создаст 'ConcurrentModificationException'. Кроме того, цикл 'foreach' - это не что иное, как« Итератор »внутри. – chucktator

0

Если вы используете Java 8 функций, что-то подобное может служить, и может быть быстрее:

List<String[]> brandList = readCsvFile("/tmp/brand.csv"); 
List<String[]> themeList = readCsvFile("/tmp/theme.csv"); 

// Extract unique values of the first column from the brand list 
// into a structure suited for fast lookup 
Set<String> names = brandList.stream() 
     .map(columns -> columns[0]) 
     .collect(Collectors.toSet()) 

// Remove all entries from themeList where the value of the 
// first column exists in names 
themeList.removeIf(columns -> names.contains(columns[0])) 
Смежные вопросы