0

我有两个列表嵌套for循环,当我匹配内部项目,我想要删除它,使性能会上升。如何删除列表中的项目?

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

当你迭代它,它是一个foreach循环在Java中本质上是做你不能从Collection删除项目。你必须创建一个新的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(文档,删除);内外循环? – 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

这就是为什么break被注释掉的原因:) –

+0

这段代码也会产生'ConcurrentModificationException'。另外,'foreach'循环在内部不过是一个'Iterator'。 – 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]))