关于java:查找集合中具有给定属性的所有对象

Finding all objects that have a given property inside a collection

本问题已经有最佳答案,请猛点这里访问。

我有一些复杂的物体,比如一只猫,它有很多特性,比如年龄,最喜欢的猫食等等。

一组猫被储存在一个Java集合中,我需要找到所有3岁的猫,或者那些最喜欢猫咪食物的猫咪。当然,我可以编写一个自定义方法来查找具有特定属性的cats,但是对于许多属性,这会变得很麻烦;是否有一些通用的方法来执行此操作?


尝试Commons Collections API:

1
2
3
4
5
6
7
8
9
List<Cat> bigList = ....; // master list

Collection<Cat> smallList = CollectionUtils.select(bigList, new Predicate() {
    public boolean evaluate(Object o) {
        Cat c = (Cat)o;
        return c.getFavoriteFood().equals("Wiskas")
            && c.getWhateverElse().equals(Something);
    }
});

当然,您不必每次都使用匿名类,您可以为常用的搜索创建Predicate接口的实现。


我一直在使用谷歌收藏(现在称为guava)来解决这类问题。有一个名为iterables的类,它可以将名为predicate的接口作为方法的参数,这真的很有用。

1
2
3
Cat theOne = Iterables.find(cats, new Predicate<Cat>() {
    public boolean apply(Cat arg) { return arg.age() == 3; }
});

在这里检查一下!


一个Java的东西你可以做8表达兰布达样

1
2
3
cats.stream()
    .filter( c -> c.getAge() == 3 && c.getFavoriteFood() == WHISKAS )
    .collect(Collectors.toList());

conceptually 51%为番石榴一样的方法,但它看起来很清洁,λ

答案可能是困难的,但一个有效的价值和手术需要注意与人相似。:)


您可以编写一个方法,该方法采用定义check(Cat)方法的接口实例,在该接口实例中,可以使用您想要的任何属性检查来实现该方法。

更好的是,使其通用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface Checker<T> {
    public boolean check(T obj);
}

public class CatChecker implements Checker<Cat> {
    public boolean check(Cat cat) {
        return (cat.age == 3); // or whatever, implement your comparison here
    }
}

// put this in some class
public static <T> Collection<T> findAll(Collection<T> coll, Checker<T> chk) {
    LinkedList<T> l = new LinkedList<T>();
    for (T obj : coll) {
         if (chk.check(obj))
             l.add(obj);
    }
    return l;
}

当然,正如其他人所说,这就是关系数据库的用途……


我建议使用jxpath,它允许您像使用xpath一样对对象图进行查询。

1
2
JXPathContext.newContext(cats).
     getValue("//*[@drinks='milk']")


同样,使用Commons Collections API:单独实现谓词时,将获得"checker"类型代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CatPredicate implements Predicate {

    private int age;


    public CatPredicate(int age) {
        super();
        this.age = age;
    }


    @Override
    public boolean evaluate(Object o) {
        Cat c (Cat)o;
        return c.getAge()==this.age;
    }

}

用作:

1
CollectionUtils.filter(catCollectionToFilter, new CatPredicate(3))


你可以使用lambdaj。这些琐碎的东西一样,是非常光滑的语法:

1
2
3
4
5
6
Person me = new Person("Mario","Fusco", 35);
Person luca = new Person("Luca","Marrocco", 29);
Person biagio = new Person("Biagio","Beatrice", 39);
Person celestino = new Person("Celestino","Bellone", 29);
List<Person> meAndMyFriends = asList(me, luca, biagio, celestino);
List<Person> oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends);

你可以做更复杂的事情。它使用的hamcrest匹配器。我想认为这不是Java的风格,但它的乐趣,这让盖伊Java知识的双位的功能编程。有一个看的源代码,所以它不是科幻小说。


只是你有没有其他的答案3到这个问题,使用番石榴,但没有答案的问题。提问者希望安切洛蒂说"嘿猫找到一个匹配的所有物业,例如时代3。一只Iterables.find想匹配,如果任何存在。你会需要使用Iterables.filter实现这番石榴,如果使用,例如:

1
2
3
4
5
6
Iterable<Cat> matches = Iterables.filter(cats, new Predicate<Cat>() {
    @Override
    public boolean apply(Cat input) {
        return input.getAge() == 3;
    }
});

使用共享的集合:

1
2
3
EqualPredicate nameEqlPredicate = new EqualPredicate(3);
BeanPredicate beanPredicate = new BeanPredicate("age", nameEqlPredicate);
return CollectionUtils.filter(cats, beanPredicate);


使用谷歌的番石榴。

1
2
3
4
5
6
7
final int lastSeq = myCollections.size();
Clazz target = Iterables.find(myCollections, new Predicate<Clazz>() {
    @Override
    public boolean apply(@Nullable Clazz input) {
      return input.getSeq() == lastSeq;
    }
});

我想使用这个方法。


您可以在ApacheCommons项目中尝试一些通用代码。collections子项目提供用于查找与特定谓词匹配的对象以及大量谓词(equals、null、instanceof等)的代码。beanutils子项目允许您创建用于测试bean属性的谓词。

使用CollectionUtils类在集合内搜索。有一些方法可以解决这个问题,但请特别检查select()方法。使用以下类来构造谓词,或编写自己的:谓词、谓词实用程序、beanpredicate。

这有时有点麻烦,但至少是通用的!-)


您可以使用josql之类的工具,并针对集合编写"sql":http://josql.sourceforge.net/

这听起来像是你想要的,还有一个好处就是能够进行更复杂的查询。


听起来很像在.NET中使用Linq

虽然Java还没有"真正的"LINQ实现,但您可能需要查看QuaEIR,它可以很容易地描述您所描述的内容。


基于谓词、过滤器和自定义迭代器/比较器的解决方案很好,但它们不提供类似于数据库索引的解决方案。例如:我想以不同的方式搜索猫的集合:按性别、年龄和年龄,所以它看起来像两个索引:1)[性别,年龄]2)[年龄]。该索引访问的值可以散列,以实现快速查找,而不必迭代整个集合。有没有这样的解决方案?


一个很普通的问题,我没有在这里是我的代码谷歌收藏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class FindByIdPredicate implements Predicate<IDObject> {

private Long entityId;

public FindByIdPredicate(final Long entityId) {
    this.entityId = entityId;

}

@Override
public boolean apply(final IDObject input) {
    return input.getId().equals(this.entityId);
}

/**
     * Pass in the Collection
 * @param Collection
 * @return IdObject if present or null
 */

public IDObject getEntity(final Collection<? extends IDObject> collection) {

    for (IDObject idObject : collection) {
        if (this.apply(idObject)) {
            return idObject;
        }
    }
    return null;

}

/**
 * @param Set
 * @return IdObject if present or null
 */

@SuppressWarnings("unchecked")
public <T> T getEntity(final Set<? extends IDObject> set) {

    for (IDObject idObject : set) {
        if (this.apply(idObject)) {
            return (T) idObject;
        }
    }
    return null;

}

}

希望这帮助


有一个非常强大的搜索能力,番石榴,当谈到搜索型问题。例如,如果你正在寻找一个对象区域的基于它的属性,你可以考虑:

1
2
3
4
5
6
Iterables.tryFind(listOfCats, new Predicate<Cat>(){
    @Override
    boolean apply(@Nullable Cat input) {
        return"tom".equalsIgnoreCase(input.name());
    }
}).or(new Cat("Tom"));

在案件的是,它是不可能在listofcats汤姆猫,它会返回,从而允许你避免NPE。


jfilter http:/ / / / / P code.google.com jfilter套房您的需求。

jfilter是一个简单的和高性能的开源图书馆查询收集的Java豆。

关键特征

  • 支持的集合(java.util.collection,java.util.map属性和数组)。
  • 支持收集收集在任何深度。
  • 内部支持的查询。
  • parameterized支持查询。
  • CAN过滤器1万个记录在100毫秒。
  • 滤波器(查询)是没有简单的JSON格式,这样mangodb查询。以下是一些例子。
    • { {"身份证":"为乐":"10"}
      • 在对象ID是小于等于10个物业。
    • {:{"ID"的"元":["0"、"1"] }
      • 在对象标识物业是0或100。
    • {"lineitems":"lineamount { }":"1"
      • 在收集的财产型lineitems parameterized安切洛蒂lineamount equals to 1。
    • {"美元"和"身份"::{"0 n

      你可以从一个搜索列表项的功能如下。祝你好运!

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      int _searchList(List<T> list,T item) {
      int idx = -1;
      idx = Collections.binarySearch(list,item,
              new Comparator<T>() {
                  public int compare(Titm1,
                          Titm2) {

                      // key1
                      if (itm1.key1.compareTo(itm2.key1) != 0) {
                          return itm1.key2.compareTo(itm2.key2);
                      }

                      // key2
                      return itm1.key2
                              .compareTo(itm2.key2);
                  }
              });

      return idx;

      }


      下面是搜索者类的一个想法,您可以用您想要查找的特定值参数化搜索者类。

      您还可以进一步将属性的名称存储在一个具有所需值的映射中。在这种情况下,您将使用对cat类的反射来调用给定属性名的适当方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      public class CatSearcher {

        private Integer ageToFind = null;
        private String  foodToFind = null;

        public CatSearcher( Integer age, String food ) {
          this.ageToFind = age;
          this.foodToFind = food;
        }

        private boolean isMatch(Cat cat) {
          if ( this.ageToFind != null && !cat.getAge().equals(this.ageToFind) ) {
             return false;
          }
          if ( this.foodToFind != null && !cat.getFood().equals(this.foodToFind) {
             return false;
          }
          return true;
        }

        public Collection<Cat> search( Collection<Cat> listToSearch ) {
          // details left to the imagination, but basically iterate over
          // the input list, call isMatch on each element, and if true
          // add it to a local collection which is returned at the end.
        }

      }


      您可以将这些对象存储在数据库中。如果您不想让一个完整的数据库服务器产生开销,您可以使用一个嵌入的服务器,比如hsqldb。然后您可以使用Hibernate或Beankeeper(使用起来更简单)或其他ORM将对象映射到表。您一直在使用OO模型,并从数据库中获得高级存储和查询的好处。