Поиск всех объектов, имеющих заданное свойство внутри коллекции

У меня есть сложный объект, такой как Cat, который обладает многими свойствами, такими как возраст, любимая еда для кошек и т. Д.

Куча кошек хранится в коллекции Java, и мне нужно найти всех кошек, которые в возрасте 3 лет, или тех, чья любимая еда для кошек – это Вискас. Разумеется, я могу написать собственный метод, который найдет тех Кошек с определенным свойством, но это становится громоздким со многими свойствами; есть ли общий способ сделать это?

Вы можете написать метод, который принимает экземпляр интерфейса, который определяет метод check(Cat) , где этот метод может быть реализован с помощью любой требуемой проверки свойств.

Еще лучше сделать его общим:

 public interface Checker { public boolean check(T obj); } public class CatChecker implements Checker { public boolean check(Cat cat) { return (cat.age == 3); // or whatever, implement your comparison here } } // put this in some class public static  Collection findAll(Collection coll, Checker chk) { LinkedList l = new LinkedList(); for (T obj : coll) { if (chk.check(obj)) l.add(obj); } return l; } 

Конечно, как говорят другие люди, это то, что реляционные базы данных были созданы для …

Попробуйте API коллекций:

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

Конечно, вам не обязательно каждый раз использовать анонимный class, вы можете создавать реализации интерфейса Predicate для обычно используемых поисков.

Я использую Google Collections (теперь называемый Guava ) для такого рода проблем. Существует class Iterables, который может использовать интерфейс Predicate как параметр метода, который действительно полезен.

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

Проверьте это здесь !

С выражением lambda Java 8 вы можете сделать что-то вроде

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

Концептуально то же, что и подход Guava Predicate, но он выглядит намного чище с лямбдой

Вероятно, это не действительный ответ для OP, но стоит отметить для людей с аналогичной потребностью. 🙂

Я предлагаю использовать Jxpath , он позволяет вам делать запросы на графах объектов, как если бы он был где xpath

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

Опять же с коллекциями коллекций API: вы получаете код типа «checker», когда вы реализуете Predicate отдельно: –

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

Вы можете использовать lambdaй . Такие вещи тривиальны, синтаксис действительно гладок:

 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 meAndMyFriends = asList(me, luca, biagio, celestino); List oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends); 

и вы можете делать гораздо более сложные вещи. Он использует hamcrest для Матчи. Некоторые будут утверждать, что это не стиль Java, но весело, как этот парень скрутил Java, чтобы сделать немного функционального программирования. Посмотрите также на исходный код, это довольно научно-фантастический.

Использование коллекций Commons:

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

Только FYI есть еще 3 ответа на этот вопрос, которые используют Guava, но никто не отвечает на вопрос. Ассистент сказал, что хочет найти всех кошек с подходящим свойством, например, возраст 3. Iterables.find будет соответствовать только одному, если таковые имеются. Для этого вам понадобится использовать Iterables.filter если вы используете Guava, например:

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

Похоже на то, что вы используете LINQ для .NET.

Хотя для Java нет «реальной» реализации LINQ, вам может потребоваться взглянуть на Quaere, который мог бы делать то, что вы описываете достаточно легко.

Вы можете использовать что-то вроде JoSQL и писать «SQL» для своих коллекций: http://josql.sourceforge.net/

Это похоже на то, что вы хотите, с дополнительным преимуществом, позволяющим выполнять более сложные запросы.

Вы можете попробовать некоторые из общего кода в проекте Apache Commons. Подпроект Collections предоставляет код для поиска объектов, которые соответствуют конкретному Predicate, а также большое количество предикатов (равно, null, instanceof и т. Д.). Подпроект BeanUtils позволяет создавать предикаты, проверяющие свойства bean-компонентов.

Используйте class CollectionUtils для поиска в коллекции. Для этого существует несколько методов, но, в частности, проверьте метод select (). Используйте следующие classы для построения предикатов или напишите свои собственные: Predicate , PredicateUtils , BeanPredicate .

Все это иногда немного громоздко, но, по крайней мере, это общий характер! 🙂

Решения, основанные на предикатах, фильтрах и пользовательских iteratorах / компараторах, хороши, но они не обеспечивают аналог с индексом базы данных. Например: я хотел бы искать коллекцию кошек по-разному: по полу и возрасту и по возрасту, поэтому он выглядит как два индекса: 1) [пол, возраст] 2) [возраст]. Значения, доступ к которым по этим индексам могут быть hashированы, для быстрого поиска, без повторения всей коллекции. Где-нибудь есть такое решение?

Используйте Google Guava.

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

Я думаю использовать этот метод.

Вы можете сохранить эти объекты в базе данных. Если вы не хотите накладных расходов на полномасштабный сервер базы данных, вы можете использовать встроенный, такой как HSQLDB. Затем вы можете использовать Hibernate или BeanKeeper (более простой в использовании) или другой ORM для сопоставления объектов с таблицами. Вы продолжаете использовать модель OO и получаете расширенные возможности хранения и запросов из базы данных.

Вот идея для поискового classа, который вы можете параметризовать с определенными значениями, которые вы хотите найти.

Вы можете пойти дальше и сохранить имена свойств, возможно, на карте с требуемыми значениями. В этом случае вы должны использовать reflection в classе Cat, чтобы вызвать соответствующие методы с именами свойств.

 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 search( Collection 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-компонентов.

Ключевая особенность

  • Поддержка свойств коллекции (java.util.Collection, java.util.Map и Array).
  • Поддержка коллекции внутри коллекции любой глубины.
  • Поддержка внутренних запросов.
  • Поддержка параметризованных запросов.
  • Может фильтровать 1 миллион записей за несколько минут.
  • Фильтр (запрос) задается в простом формате json, это похоже на запросы Mangodb. Ниже приведены некоторые примеры.
    • {“id”: {“$ le”: “10”}
      • где свойство id объекта меньше, чем 10.
    • {“id”: {“$ in”: [“0”, “100”]}}
      • где свойство id объекта равно 0 или 100.
    • { “lineItems”: { “lineAmount”: “1”}}
      • где свойство collectionItems параметризованного типа имеет значение lineAmount равно 1.
    • {“$ and”: [{“id”: “0”}, {“billingAddress”: {“city”: “DEL”}}]}
      • где id – значение 0, а свойство billingAddress.city – DEL.
    • {“lineItems”: {“tax”: {“key”: {“code”: “GST”}, “value”: {“$ gt”: “1.01”}}}}
      • где свойство collectionItems параметризованного типа, у которого есть свойство типа карты налогов с параметризованным типом, имеет код, равный значению GST, превышающему 1.01.
    • {‘$ или’: [{‘code’: ’10’}, {‘skus’: {‘$ and’: [{‘price’: {‘$ in’: [’20’, ’40’]} }, {‘code’: ‘RedApple’}]}}]}
      • Выберите все продукты, в которых код продукта равен 10 или sku в 20 и 40, а код sku – «RedApple».

У Guava есть очень мощные возможности поиска, когда дело доходит до таких проблем. Например, если ваша область ищет объект на основе одного из его свойств, вы можете подумать:

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

в случае, если возможно, что Tom cat не находится в спискеOfCats, он будет возвращен, что позволит вам избежать NPE.

Очень распространенная проблема, и я использовал сбор google, и вот мой код

 public class FindByIdPredicate implements Predicate { 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 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 getEntity(final Set set) { for (IDObject idObject : set) { if (this.apply(idObject)) { return (T) idObject; } } return null; } 

}

Надеюсь это поможет

вы можете искать элемент из списка следующим образом. удачи!

 int _searchList(List list,T item) { int idx = -1; idx = Collections.binarySearch(list,item, new Comparator() { 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; 

}

  • Коллекции. Сорт с несколькими полями
  • Итерация через список в обратном порядке в java
  • Самый простой способ объединить два списка в карту (Java)?
  • Реализация бинарного поиска в объектах
  • Как использовать Collections.sort () в Java? (Конкретная ситуация)
  • Двунаправленный словарь от 1 до 1 в C #
  • Как инициализировать значения HashSet по построению?
  • Как выполнить поиск в списке объектов Java
  • Почему нет ConcurrentHashSet против ConcurrentHashMap
  • Почему в Java нет SortedList?
  • Как переопределить метод добавления List на C #?
  • Давайте будем гением компьютера.