循环List <string>并删除项</string>的更好方法

时间:2015-01-15 17:54:33

标签: java

我有一个列表,如果匹配,我会循环删除列表中的项目。 如果列表中的项目被删除,我使用i = -1。但它又从头开始循环。有更好的方法吗?

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");
}

6 个答案:

答案 0 :(得分: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();
    }
}

答案 1 :(得分:1)

您可以使用具有删除方法的Iterator接口。

    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();
        }
    }

答案 2 :(得分:1)

使用Java-8,您可以简化整个过程:

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

我认为这是通过逐个检查项目从列表中删除项目的最短路径。 (我的意思是&#39;最短的代码大小,而不是复杂性)。

答案 3 :(得分:1)

当您使用索引迭代列表时,如果要从列表中删除项目,则需要注意如何处理索引。 (在@ dasblinkenlight的答案中通过迭代器执行remove在这种情况下更好,但还有其他类似的情况,这是不可能的。)

假设您刚刚删除了重置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);
    } 
}

在元素移位时没有问题。

答案 4 :(得分:0)

使用迭代器。

Iterator的Javadoc说以下

迭代器允许调用者在迭代期间使用明确定义的语义从底层集合中删除元素。

答案 5 :(得分:0)

或者您可以使用guava API来实现它。

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();