Search for all objects that have the specified property within the collection.

I have a complex object such as Cat, which has many properties, such as age, favorite food for cats, etc.

The bouquet of cats is stored in the Java collection, and I need to find all cats that are 3 years old, or those whose favorite food for cats is Whiskas. Of course, I can write my own method that will find those Cats with a certain property, but it becomes cumbersome with many properties; Is there a general way to do this?

+80
java collections
Feb 25 '09 at 19:15
source share
20 answers

You can write a method that accepts an instance of an interface that defines a check(Cat) method, where this method can be implemented using any required property check.

Better yet, make it general:

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

Of course, as other people say, this is what relational databases were created for ...

+41
Feb 25 '09 at 19:19
source share

Try the collection collections 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); } }); 

Of course, you don't have to use an anonymous class every time; you can create implementations of the Predicate interface for commonly used searches.

+61
Feb 25 '09 at 23:45
source share

I use Google Collections (now called Guava ) for this kind of problem. There is a class called Iterables that can use the Predicate interface as a parameter to a method that is really useful.

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

Check here !

+54
Feb 25 '09 at 23:40
source share

With Java 8 lambda expression you can do something like

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

Conceptually the same as Guava Predicate approach, but it looks a lot cleaner with lambda

Probably not the right answer for the OP, but worth noting for people with a similar need. :)

+43
May 24 '13 at 4:18
source share

I suggest using Jxpath , it allows you to make queries on object graphs, as if it is where xpath is like

 JXPathContext.newContext(cats). getValue("//*[@drinks='milk']") 
+11
Feb 25 '09 at 19:41
source share

Again with collections of API collections: you get code like "checker" while Predicate is executed: -

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

which is used as: -

 CollectionUtils.filter(catCollectionToFilter, new CatPredicate(3)) 
+5
Mar 10 '10 at 12:00
source share

You can use lambdaj . Such things are trivial, the syntax is really smooth:

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

and you can do much more complex things. It uses hamcrest for matches. Some argue that this is not a Java style, but it's funny how this guy twisted Java to do a bit of functional programming. Look also at the source code, which is pretty sci-fi.

+3
Dec 06 '13 at 11:12
source share

Using Commons Collections:

 EqualPredicate nameEqlPredicate = new EqualPredicate(3); BeanPredicate beanPredicate = new BeanPredicate("age", nameEqlPredicate); return CollectionUtils.filter(cats, beanPredicate); 
+2
Aug 29 '13 at 11:37
source share

Just FYI there are 3 other answers to this question that use Guava, but no one answers the question. The applicant said that he wants to find all Cats with the corresponding property, for example. age 3. Iterables.find will match only one, if any. To achieve this, you will need Iterables.filter if you are using Guava, for example:

 Iterable<Cat> matches = Iterables.filter(cats, new Predicate<Cat>() { @Override public boolean apply(Cat input) { return input.getAge() == 3; } }); 
+2
Jul 31 '16 at 16:19
source share

It sounds very similar to using LINQ for .NET.

While there is no “real” LINQ implementation for java, you can look at Quaere , which could do what you describe quite easily.

+1
Feb 25 '09 at 19:25
source share

You can use something like JoSQL and write "SQL" for your collections: http://josql.sourceforge.net/

Sounds the way you want, with the added benefit of allowing you to perform more complex queries.

+1
Feb 25 '09 at 19:28
source share

You can try some of the common code in the Apache Commons project. The Collections subproject provides code for finding objects matching a specific Predicate, as well as a large number of predicates (equal to null, instanceof, etc.). The BeanUtils subproject allows you to create predicates that test the properties of beans.

Use the CollectionUtils class to search the collection. There are several methods for this, but in particular, check the select () method. Use the following classes to build predicates or write your own: Predicate , PredicateUtils , BeanPredicate .

This is sometimes a little cumbersome, but at least it's generic !:-)

+1
Feb 25 '09 at 19:30
source share

Solutions based on predicates, filters, and custom iterators / comparators are good, but they do not provide a counterpart to the database index. For example: I would like to look for a collection of cats in different ways: by sex and age and by age, so that it looks like two indexes: 1) [gender, age] 2) [age]. Values ​​accessed by these indices can be hashed for quick search, without repeating the entire collection. Is there such a solution somewhere?

+1
May 6 '10 at 12:13
source share

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

I am thinking of using this method.

+1
May 24 '13 at 2:08
source share

You can save these objects in the database. If you do not want the overhead of a full-blown database server, you can use a built-in, such as HSQLDB. Then you can use Hibernate or BeanKeeper (easier to use) or another ORM to map objects to tables. You continue to use the OO model and get advanced storage and query capabilities from the database.

0
Feb 25 '09 at 19:23
source share

Here is an idea for a search class that you could parameterize with the specific values ​​you want to find.

You can go further and save the property names, as well as possibly on a map with the required values. In this case, you should use the reflection of the Cat class to call the appropriate methods with property names.

 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. } } 
0
Feb 25 '09 at 19:33
source share

JFilter http://code.google.com/p/jfilter/ meets your requirements.

JFilter is a simple and high-performance open source library for querying the Java beans collection.

Main functions

  • Support for collection properties (java.util.Collection, java.util.Map and Array).
  • Support for the collection inside the collection of any depth.
  • Support for internal queries.
  • Support for parameterized queries.
  • Can filter 1 million records in a few minutes.
  • The filter (request) is set in a simple json format, this is similar to Mangodb requests. Below are some examples.
    • {"id": {"$ le": "10"}
      • where the id property of the object is less than 10.
    • {"id": {"$ in": ["0", "100"]}}
      • where the id property of the object is 0 or 100.
    • {"lineItems": {"lineAmount": "1"}}
      • where the collectionItems property of the parameterized type has a lineAmount value of 1.
    • {"$ and": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
      • where id is the value 0, and the billingAddress.city property is DEL.
    • {"lineItems": {"tax": {"key": {"code": "GST"}, "value": {"$ gt": "1.01"}}}}
      • where the collectionItems property of a parameterized type, which has a tax card type property with a parameterized type, has a code equal to a GST value greater than 1.01.
    • {'$ or': [{'code': '10'}, {'skus': {' $ and ': [{' price ': {' $ in ': [' 20 ', '40']} }, {'code': 'RedApple'}]}}}]}
      • Select all products where the product code is 10 or sku is 20 and 40 and the sku code is "RedApple".
0
Apr 05 2018-12-12T00:
source share

Guava has very powerful search capabilities when it comes to such problems. For example, if your area is looking for an object based on one of its properties, you might consider:

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

if it is possible that Tom cat is not in the OfCats list, it will be returned, which will allow you to avoid NPE.

0
Sep 24
source share

A very common problem and I used google collection and here is my code

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

}

Hope this helps

0
May 14 '13 at 14:58
source share

You can search for an item from a list as follows. good luck!

 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; 

}

0
Jun 27 '13 at 4:05
source share



All Articles