查找集合中具有给定属性的所有对象

我有一些复杂的东西,比如猫,它有很多属性,比如年龄,喜欢的猫食等等。

一堆猫被存储在一个Java集合中,我需要find所有三岁的猫,或者那些最喜欢的猫食是Whiskas的猫。 当然,我可以编写一个自定义的方法来find那些具有特定属性的猫,但是这会让许多属性变得繁琐; 有没有一些通用的方式来做到这一点?

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

更好的是,使其通用:

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

当然,就像其他人所说的那样,这就是关系数据库的作用。

尝试公共收集API:

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

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

我一直在使用Google Collections(现在称为Guava )来解决这类问题。 有一个名为Iterables的类,可以将一个名为Predicate的接口作为一个真正有用的方法的参数。

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

在这里检查!

有了Java 8 lambdaexpression式,你可以做类似的事情

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

从概念上讲,与“番石榴谓词”(Guava Predicate)方法一样,但使用lambda看起来更清晰

可能不是OP的有效答案,但值得注意的是有类似需求的人。 🙂

我build议使用Jxpath ,它允许你在对象图上做查询,就好像它在xpath那样

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

再次使用公共集合API:当您单独实现谓词时,您将获得“检查器”types的代码: –

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

它被用作: –

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

你可以使用lambdaj 。 像这样的事情是微不足道的,语法是非常顺利的:

 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为Matchers 。 有人会认为这不是Java风格,但是这个家伙如何扭曲Java来做一些function性编程是很有趣的。 也看看源代码,这是相当科幻。

使用Commons Collections:

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

只是FYI有3个其他答案给这个问题,使用番石榴,但没有回答这个问题。 提问者表示,他希望find所有具有匹配属性的猫,例如3岁Iterables.find将只匹配一个,如果存在的话。 例如,如果使用番石榴,则需要使用Iterables.filter来实现此目的。

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

听起来很像你将在.NET中使用LINQ的东西

尽pipejava还没有“真正的”LINQ实现,但是你可能想看一下Quaere ,它可以做你所描述的足够简单的东西。

你可以使用诸如JoSQL之类的东西,并且对你的集合写'SQL': http ://josql.sourceforge.net/

这听起来像你想要的,能够做更复杂的查询的额外好处。

您可以尝试Apache Commons项目中的一些通用代码。 Collections子项目提供用于查找匹配特定Predicate的对象的代码,以及大量的谓词(equals,null,instanceof等)。 BeanUtils子项目允许您制定testingBean属性的谓词。

使用CollectionUtils类在集合中进行search。 有几个方法,但特别是检查select()方法。 使用以下类构造谓词,或者编写自己的谓词 : PredicateUtils , BeanPredicate 。

这有时候有点麻烦,但至less是通用的! 🙂

基于谓词,filter和自定义迭代器/比较器的解决scheme很好,但是它们不提供数据库索引的模拟。 例如:我想按照不同的方式search猫的收集方式:按性别,年龄和年龄,看起来像两个指标:1)[性别,年龄] 2)[年龄]。 可以对由该索引访问的值进行散列,以实现快速查找,而无需迭代整个集合。 有没有这样的解决scheme?

使用Google Guava。

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

我想用这个方法。

您可以将这些对象存储在数据库中。 如果你不想要一个完整的数据库服务器的开销,你可以使用像HSQLDB这样的embedded式数据库服务器。 然后,您可以使用Hibernate或BeanKeeper(更简单易用)或其他ORM将对象映射到表。 您继续使用OO模型并从数据库获取高级存储和查询优势。

这里有一个search类的想法,你可以参数化你想要查找的特定值。

你可以进一步存储这些属性的名字,可能在一个具有所需值的地图中。 在这种情况下,您将使用Cat类的reflection来调用给定属性名称的适当方法。

 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. } } 

JFilter http://code.google.com/p/jfilter/套装您的需求。;

JFilter是一个简单而高性能的开源库,用于查询Java bean的集合。

主要特征

  • 支持collection(java.util.Collection,java.util.Map和Array)属性。
  • 支持任何深度收集里面的集合。
  • 支持内部查询。
  • 支持参数化查询。
  • 可以在几百毫秒内过滤100万条logging。
  • filter(查询)以简单的json格式给出,就像Mangodb查询一样。 以下是一些例子。
    • {“id”:{“$ le”:“10”}
      • 对象id属性小于等于10。
    • {“id”:{“$ in”:[“0”,“100”]}}
      • 对象id属性是0或100。
    • { “了LineItem”:{ “lineAmount”: “1”}}
      • 其中参数化types的lineItems集合属性的lineAmount等于1。
    • {“$ and”:[{“id”:“0”},{“billingAddress”:{“city”:“DEL”}}]}
      • 其中id属性为0,而billingAddress.city属性为DEL。
    • {“lineItems”:{“taxes”:{“key”:{“code”:“GST”},“value”:{“$ gt”:“1.01”}}}}
      • 其中具有参数化types的参数化types的lineItems集合属性的代码等于大于1.01的GST值。
    • {'$ or':[{'code':'10'},{'skus':{'$ and':[{'price':{'$ in':['20','40']} },{'code':'RedApple'}]}}]}
      • select产品代码为10或sku价格为20,40的所有产品,sku代码为“RedApple”。

当涉及到这类问题时,番石榴具有非常强大的search能力。 例如,如果您的区域根据其中一个属性search对象,则可能会考虑:

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

如果可能Tom猫不在listOfCats中,它将被返回,从而允许你避免NPE。

一个非常常见的问题,我用谷歌collections,这里是我的代码

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

}

希望这可以帮助

您可以从列表中search项目如下function。 祝你好运!

 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; 

}