从 Java 集合中过滤元素的简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3657485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 03:15:25  来源:igfitidea点击:

Easy way to filter elements from a collection in Java?

javacollections

提问by Frederik

I want to write a method that removes all elements from a collection that follow a certain pattern. In functional languages, I would use filter()with a lambda expression. However, in Java, it seems I'm stuck with this:

我想编写一个方法,从集合中删除遵循特定模式的所有元素。在函数式语言中,我会将filter()与 lambda 表达式一起使用。然而,在 Java 中,我似乎坚持这个:

public void removeAllBlueCars() {
    LinkedList<Car> carsToRemove = new LinkedList<Car>();
    for (Car c : cars) {
        if (c.getCarColor() == Color.BLUE) {
            carsToRemove.add(c);
        }
    }
    cars.removeAll(carsToRemove );
}

Removing elements directly causes a ConcurrentModificationException. Is there a better way to do this without resorting to Google Collections?

删除元素直接导致 ConcurrentModificationException。在不求助于Google Collections 的情况下,有没有更好的方法来做到这一点?

采纳答案by Péter T?r?k

You could iterate through the list using a ListIterator, which has a removemethod.

您可以使用ListIterator具有remove方法的a 遍历列表。

Btw you should declare your list as List<Car>- program for interfaces, not implementation.

顺便说一句,您应该将列表声明为List<Car>- 接口程序,而不是实现程序。

回答by Alberto Zaccagni

See if lambdaj's filter option can help you.

看看lambdaj的过滤器选项是否可以帮助您。

回答by Vivien Barousse

Maybe you could use iterators, which are a little more efficient:

也许你可以使用更高效的迭代器:

public void removeAllBlueCars() {
    Iterator<Car> carsIterator = cars.iterator();
    while (carsIterator.hasNext()) {
        Car c = carsIterator.next();
        if (c.getCarColor() == Color.BLUE) {
            carsIterator.remove();
        }
    }
}


Also, if you want to make this solution more generic, I'd suggest you something like:

另外,如果你想让这个解决方案更通用,我建议你这样做:

public interface Filter<T> {

    public boolean shouldRemove(T t);

}

And you could use it like this:

你可以像这样使用它:

public void removeCars(Filter<Car> filter) {
    Iterator<Car> carsIterator = cars.iterator();
    while (carsIterator.hasNext()) {
        Car c = carsIterator.next();
        if (filter.shouldRemove(c)) {
            carsIterator.remove();
        }
    }
}

Your method gets called like this:

你的方法被这样调用:

removeCars(new Filter<Car>() {

    public boolean shouldRemove(Car car) {
        return car.getCarColor() == Color.BLUE;
    }

});

回答by Marcus Johansson

You could always go backwards and delete the elements..

你总是可以倒退并删除元素..

    for (int i = array.size() - 1; i >= 0; i--) {
       if (array.get(i).getCarColor() == Color.BLUE)
                array.remove(i);
    }

edit: Noticed it was a LinkedList which might make my answer a bit non-relevant.

编辑:注意到它是一个 LinkedList,这可能会使我的答案有点不相关。

回答by gpeche

You can use CollectionUtils.filter(). It works with an Iterator, so it should have no problems removing items directly from the Collection. It is another dependency though. If you want the code standalone it would be:

您可以使用CollectionUtils.filter()。它适用于Iterator,因此直接从Collection. 不过,这是另一种依赖。如果您希望代码独立,它将是:

public interface Predicate {
    boolean evaluate(Object o);
}

public static void filter(Collection collection, Predicate predicate) {
if ((collection != null) && (predicate != null))
    for (Iterator it = collection.iterator(); it.hasNext(); )
        if (!predicate.evaluate(it.next()))
            it.remove();
}
...
filter(collection, new Predicate() {
    public boolean evaluate(Object o) { return whatever; }
});

回答by romacafe

I'm a big fan of the Iterator solution provided by Vivien Barousse and gpeche. But I wanted to point out that you don't have to actually remove any elements from the collection, you just need to prevent the filter from returning them. That way, you basically have multiple views of the same collection, which can be very convenient and efficient. The Filter object is basically your lamda expression, or as close as you're gonna get in Java until version 7...

我非常喜欢 Vivien Barousse 和 gpeche 提供的 Iterator 解决方案。但我想指出的是,您实际上不必从集合中删除任何元素,您只需要阻止过滤器返回它们即可。这样,您基本上可以拥有同一个集合的多个视图,这会非常方便和高效。Filter 对象基本上是您的 lamda 表达式,或者与您在 Java 版本 7 之前将要获得的一样接近......

回答by Jeffrey Bosboom

With Java 8, you can filter with a lambda expression using Collection.removeIf.

使用 Java 8,您可以使用 lambda 表达式进行过滤Collection.removeIf

cars.removeIf(c -> c.getCarColor() == Color.BLUE);

回答by jwir3

For those of you who come across this thread and might be working on Android with RxJava/RxAndroid, there's a quick way to do this without adding the Apache Commons Collections dependency:

对于那些遇到这个线程并且可能正在使用 RxJava/RxAndroid 在 Android 上工作的人,有一种快速的方法可以做到这一点,而无需添加 Apache Commons Collections 依赖项:

cars = Observable.from(cars).filter(car -> {
  if (car.getCarColor() == Color.BLUE) {
    return false;
  }

  return true;
}).toList().toBlocking().first();

Note that I also happen to be using lambda expressions with Retrolambda. If you aren't using Retrolambda, you can express the same thing using the following:

请注意,我也碰巧在Retrolambda 中使用了 lambda 表达式。如果您不使用 Retrolambda,则可以使用以下内容表达相同的内容:

cars = Observable.from(cars).filter(new Func1<Car, Boolean>() {
      @Override
      public Boolean call(Car car) {
        if (car.getCarColor() == Color.BLUE) {
          return false;
        }

        return true;
      }
}).toList().toBlocking().first();

回答by Popinjoy

It's really an old post but how abt using the way given in Oracle Java tutorial.

这确实是一篇旧帖子,但是如何使用 Oracle Java 教程中给出的方式。

static void filter(Collection<?>c) {
    for (Iterator<?>it = c.iterator(); it.hasNext(); )
         if (!cond(it.next()))
             it.remove();
}

回答by Ilya Gazman

Here is the Android way to implement a generic solution for this:

这是为此实现通用解决方案的Android方法:

Usage:

用法:

Remove all null strings from my list

从我的列表中删除所有空字符串

    LinkedList<String> list = ...
    ListUtils.filter(list, new ListUtils.Filter<String>() {
        @Override
        public boolean keepItem(String item) {
            return item != null;
        }
    });

Source:

来源:

public class ListUtils {
    public interface Filter<T>{
        boolean keepItem(T item);
    }

    public static <T> void filter(@NonNull List<T> items, @NonNull Filter<T> filter) {
        for (Iterator<T> iterator = items.iterator(); iterator.hasNext();){
            if(!filter.keepItem(iterator.next())){
                iterator.remove();
            }
        }
    }
}