Java Collection过滤

时间:2009-11-24 12:14:48

标签: java collections

我有这样的事情:

public class Foo {
  public String id;
}

Vector<Foo> foos;

我需要通过id从集合中获取一个对象。

在C#中,我会这样做:foos.Where(o => o.id = 7)

在Java中最好的方法是什么?

11 个答案:

答案 0 :(得分:11)

首先,我建议使用ArrayList<Foo>而不是Vector<Foo> - ArrayList几乎总是优先于Vector

使用Google Collections API,尤其是Iterables.filter。它现在非常笨重 - 你需要预先设置谓词,或者使用匿名内部类,因为缺少lambda表达式。此外,Java没有扩展方法,因此您将调用Iterables.filter(collection, predicate)而不是collection.filter(predicate)。在Java 7中,这些都会有所简化。

请注意,使用filter会找到Iterable<Foo> - 如果您只需要第一个匹配项,请改用Iterables.find,这相当于LINQ中的Enumerable.First<T>(Func<T, bool>)。< / p>

答案 1 :(得分:6)

使用Google Collections,即:

Lists.newArrayList(Iterables.filter(foos, new Predicate<Foo>() {
  public boolean apply(Foo input) {
    return input != null && "7".equals(input.id);
  }
}));

Iterables.filter (以及 Collections2.filter ,它也会这样做)为您提供过滤集合的实时视图,就像seh的概念一样,但代码更少。为了再次创建列表,我将其传递给Google Collection的 List 实用程序类的 newArrayList 方法。

就像其他人一样,我强烈建议不要使用Vector作为声明。相反,请尝试使用最通用的类​​型,例如 List&lt; Foo&gt; 或甚至 Collection&lt; Foo&gt; 。此外,除非您需要 Vector 的同步功能,否则请使用 ArrayList (或其他适合此问题的类型)。

答案 2 :(得分:5)

您可能希望将数据存储在Map&lt; Integer,Foo&gt;中。而不是List&lt; Foo&gt;。例如,TreeMap将按排序顺序保存所有内容。

答案 3 :(得分:3)

首先,请勿使用Vector,请使用ArrayList

ArrayList< Widget > widgets = ...

Widget found = null;

for ( Widget o : widgets )
{
  if ( o.id == 7 )
  {
    found = o;
    break;
  }

}

答案 4 :(得分:1)

Collection.binarySearch(List<T extends Comparable>, T key);

您传递了您的集合,以及密钥(id或其他),并且该方法返回您的对象。您的对象的类必须实现Comparable接口。

注意:在调用binarySearchCollections.sort(..)

之前,必须对集合进行排序

答案 5 :(得分:1)

如果您有一个ArrayList(或类似的东西 - 即来自Collection库的东西),那么Apache Commons Collections有很多用于过滤/迭代等的工具。

请注意,与Jon的答案中引用的Google Collections库不同,不支持泛型。

答案 6 :(得分:1)

我认为,Java中的传统方式是遍历列表并使用您查找的ID搜索Foo(复杂度O(n))。如果这样做很慢,您可以考虑使用HashMap结构将foo映射到其索引。

可以通过继承集合类来隐藏查找:

public class ListOfFoos extends ArrayList<Foo> {

  public Foo getFooByIndex(String index) {
    // do your lookup here
  }

}

从现在开始使用ListOfFoos而不是ArrayList作为新的Collection类型,允许通过索引号直接访问Foo。

答案 7 :(得分:1)

看看lambdaj。它允许以伪功能和非常易读的方式操作,过滤,排序,聚合集合。

答案 8 :(得分:0)

以下类型提供序列过滤。这个解决方案是通用的,但不太适合于集合或排序序列,每个集合或排序序列都提供了更有效的方法来查找和删除与某些示例相匹配的元素。

首先,定义一个Iterator类型,它实际上是一个懒惰的生成器适配器:

abstract class IteratorHusk<T> implements Iterator<T>
{
  @SuppressWarnings("unchecked")
  protected IteratorHusk()
  {
    value_ = nil();
  }


  @SuppressWarnings("unchecked")
  protected T nil()
  {
    return (T) NIL;
  }


  protected abstract T yield();


  private boolean tryPop()
  {
    value_ = yield();
    return NIL != value_;
  }


  @SuppressWarnings("unchecked")
  private T take()
  {
    final T current = value_;
    value_ = (T) NIL;
    return current;
  }


  public final boolean hasNext()
  {
    return NIL != value_ || tryPop();
  }


  public final T next()
  {
    if (NIL == value_ && !tryPop())
    {
      throw new NoSuchElementException();
    }
    return take();
  }


  public void remove()
  {
    throw new UnsupportedOperationException();
  }


  // We want to tolerate null as a possibly valid value.
  private static final Object NIL = new Object();
  private T value_;
}

这是2009年,Java仍然缺乏关闭和一流的功能,所以我们羞怯地介绍了这个家庭:

interface UnaryFunction<T, U>
{
  T eval(U argument);
}

现在,围绕一元谓词包装生成器以构建序列过滤器:

class FilteringIterator<T> extends IteratorHusk<T>
{
  public FilteringIterator(Iterator<? extends T> iter,
                           UnaryFunction<Boolean, ? super T> pred)
  {
    iter_ = iter;
    pred_ = pred;
  }


  @Override
  protected T yield()
  {
    while (iter_.hasNext())
    {
      final T val = iter_.next();
      if (!pred_.eval(val))
      {
        return val;
      }
    }
    return nil();
  }


  private final Iterator<? extends T> iter_;
  private final UnaryFunction<Boolean, ? super T> pred_;
}

现在,公开一个便利功能:

public static <T>
Iterator<T> lazyFilter(UnaryFunction<Boolean, ? super T> pred,
                       Iterator<? extends T> source)
{
  return new FilteringIterator<T>(source, pred);
}

答案 9 :(得分:0)

来自sweetener项目的限制类解决了这个问题。

示例:

Collection<Foo> filteredList = Collections.filter(foos, Criteria.newCriteria().add(Restrictions.equals("id", 7)));

Other examples

答案 10 :(得分:0)

如果您的集合已经排序,您可以利用二进制搜索,它会给出最坏情况下的复杂度O(log n):

Collection.binarySearch(List<T extends Comparable>, T key);

如果您可以自由选择数据结构,请使用HashMap<String, Object>,这会给您带来O(1)的复杂性。

ps:使用ArrayList代替Vector