Я хочу отфильтровать java.util.Collection на основе предиката.




Используйте CollectionUtils.filter (Коллекция, Предикат) из Apache Commons.
В CollectionUtils есть и другие методы фильтрации, которые не изменяют исходную коллекцию.
В частности, метод, который нет изменяет коллекцию на месте, - это org.apache.commons.collections.CollectionUtils # select (Collection, Predicate)
В Commons Collections v4 теперь используются Generics.
Этот метод следует использовать с осторожностью, поскольку он полагается (по крайней мере, в реализации commons-collections-3.2.1) на метод iterator.remove (), который является необязательным для коллекций, поэтому вместо фильтрации, скажем, массива вы можете получить исключение UnsupportedOperationException.
Рассмотрим Коллекции Google для обновленной структуры коллекций, которая поддерживает универсальные шаблоны.
ОБНОВИТЬ: библиотека коллекций Google устарела. Вместо этого вы должны использовать последнюю версию Гуава. Он по-прежнему имеет все те же расширения структуры коллекций, включая механизм фильтрации на основе предиката.
да, я знал про гугловские коллекции lib. В версии, которую я использовал, не было Collections2. Я добавил новый ответ на этот вопрос, в котором перечислены конкретные методы.
Kevin, Iterables.filter () и Iterators.filter () были там с самого начала, и обычно это все, что вам нужно.
Вы уверены, что хотите отфильтровать саму Коллекцию, а не итератор?
см. org.apache.commons.collections.iterators.FilterIterator
или используя версию 4 apache commons org.apache.commons.collections4.iterators.FilterIterator
Настройка:
public interface Predicate<T> {
public boolean filter(T t);
}
void filterCollection(Collection<T> col, Predicate<T> predicate) {
for (Iterator i = col.iterator(); i.hasNext();) {
T obj = i.next();
if (predicate.filter(obj)) {
i.remove();
}
}
}
Использование:
List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
public boolean filter(MyObject obj) {
return obj.shouldFilter();
}
});
Хорошо, но я предпочитаю реализацию Alan, потому что вы получаете копию коллекции вместо ее изменения. Более того, код Алана является потокобезопасным, а ваш - нет.
"Лучший" способ - это слишком широкая просьба. Он самый "короткий"? «Самый быстрый»? "Удобочитаемый"? Фильтр на месте или в другую коллекцию?
Самый простой (но не самый читаемый) способ - перебрать его и использовать метод Iterator.remove ():
Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
Foo foo = it.next();
if ( !condition(foo) ) it.remove();
}
Теперь, чтобы сделать его более читабельным, вы можете обернуть его в служебный метод. Затем изобрести интерфейс IPredicate, создать анонимную реализацию этого интерфейса и сделать что-нибудь вроде:
CollectionUtils.filterInPlace(col,
new IPredicate<Foo>(){
public boolean keepIt(Foo foo) {
return foo.isBar();
}
});
где filterInPlace () выполняет итерацию по коллекции и вызывает Predicate.keepIt (), чтобы узнать, следует ли сохранить экземпляр в коллекции.
Я действительно не вижу оправдания для использования сторонней библиотеки только для этой задачи.
Я голосую за это: он просто работает, без внешних библиотек. Я никогда не понимал, что создание экземпляра Iterator может быть действительно полезным по сравнению с использованием синтаксиса for-each или что вы можете удалять элементы из списка без ConcurrentModificationException или чего-то в этом роде. :)
Думаю, это лучший способ использовать стандартную библиотеку Java без копирования. В версии 1.8 будет функция stream(), но не все смогут играть с новейшими игрушками: P
Это тоже изменяет исходную коллекцию? @ZeroOne
Да, конечно, @Rohan. Попробуйте, если не верите. ;)
Ха-ха, я сделал! Но я хочу сохранить свою оригинальную коллекцию. Можете ли вы предложить способ сделать это без добавления внешней библиотеки? @ZeroOne
@ Рохан, хорошо, значит, ты хочешь новый список? Для этого см. Ответ gavenkoa с Java 8.
Предполагая, что вы используете Java 1.5 и не можете добавить Коллекции Google, я бы сделал что-то очень похожее на то, что сделали ребята из Google. Это небольшая вариация комментариев Джона.
Сначала добавьте этот интерфейс в свою кодовую базу.
public interface IPredicate<T> { boolean apply(T type); }
Его разработчики могут ответить, когда определенный предикат истинен для определенного типа. Например. Если T был User, а AuthorizedUserPredicate<User> реализует IPredicate<T>, то AuthorizedUserPredicate#apply возвращает, авторизован ли переданный в User.
Тогда в каком-нибудь служебном классе вы могли бы сказать
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
Итак, предполагая, что у вас есть использование вышеперечисленного, может быть
Predicate<User> isAuthorized = new Predicate<User>() {
public boolean apply(User user) {
// binds a boolean method in User to a reference
return user.isAuthorized();
}
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);
Если производительность при линейной проверке вызывает беспокойство, тогда мне может потребоваться объект домена с целевой коллекцией. Объект домена, который имеет целевую коллекцию, будет иметь логику фильтрации для методов, которые инициализируют, добавляют и устанавливают целевую коллекцию.
ОБНОВИТЬ:
В служебном классе (скажем, Predicate) я добавил метод выбора с опцией для значения по умолчанию, когда предикат не возвращает ожидаемое значение, а также статическое свойство для параметров, которые будут использоваться внутри нового IPredicate.
public class Predicate {
public static Object predicateParams;
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
T result = null;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
T result = defaultValue;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
}
В следующем примере выполняется поиск отсутствующих объектов между коллекциями:
List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
new IPredicate<MyTypeA>() {
public boolean apply(MyTypeA objectOfA) {
Predicate.predicateParams = objectOfA.getName();
return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
public boolean apply(MyTypeB objectOfB) {
return objectOfB.getName().equals(Predicate.predicateParams.toString());
}
}) == null;
}
});
В следующем примере выполняется поиск экземпляра в коллекции и возврат первого элемента коллекции в качестве значения по умолчанию, если экземпляр не найден:
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
ОБНОВЛЕНИЕ (после выпуска Java 8):
Прошло несколько лет с тех пор, как я (Алан) впервые опубликовал этот ответ, и я до сих пор не могу поверить, что собираю ТАК баллов за этот ответ. Во всяком случае, теперь, когда Java 8 ввела в язык замыкания, мой ответ был бы значительно другим и более простым. В Java 8 нет необходимости в отдельном статическом служебном классе. Итак, если вы хотите найти 1-й элемент, соответствующий вашему предикату.
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
JDK 8 API для дополнительных компонентов поддерживает get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier) и orElseThrow(exceptionSupplier), а также другие «монадические» функции, такие как map, flatMap и filter.
Если вы хотите просто собрать всех пользователей, которые соответствуют предикату, используйте Collectors для завершения потока в желаемой коллекции.
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
См. здесь для получения дополнительных примеров того, как работают потоки Java 8.
Да, но я ненавижу изобретать велосипед снова и снова. Я бы предпочел найти какую-нибудь служебную библиотеку, которая работает, когда захочу.
Это не лучший способ, если вам не нужна новая коллекция. Используйте метафору фильтрующего итератора, которая может входить в новую коллекцию, или это может быть все, что вам нужно.
@Nestor: в понимании Scala фильтрация была бы намного проще: val authorized = for (user <- users if user.isAuthorized) yield user
Это изменит исходную коллекцию или создаст новую? Я попытался использовать этот метод и зарегистрировал обе свои коллекции (исходную и возвращенную методом), они одинаковы. @Алан
Любая идея, если этот метод предназначен для изменения исходной коллекции. Я пробовал использовать этот метод, но он тоже отфильтровал мою оригинальную коллекцию.
@Rohan, это не предназначено для изменения исходной коллекции. Обратите внимание, что приведенная выше коллекция результатов создается заново, и метод фильтра добавляет в нее только в том случае, если применяется предикат.
Метод Collections2.filter (Коллекция, Предикат) в Библиотека Google Guava делает именно то, что вы ищете.
С помощью ForEach DSL вы можете написать
import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;
Collection<String> collection = ...
for (Select<String> each : select(collection)) {
each.yield = each.value.length() > 3;
}
Collection<String> result = $result();
Учитывая набор [Быстрый, коричневый, лиса, прыжки, за, ленивый, собака], это приводит к [быстро, коричневый, прыжки, за, ленивый], то есть все строки длиннее трех символов.
Все стили итерации, поддерживаемые ForEach DSL, являются
AllSatisfyAnySatisfyCollectCounntCutPiecesDetectGroupedByIndexOfInjectIntoRejectSelectДля получения более подробной информации, пожалуйста, обратитесь к https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach
Это довольно умно! Однако предстоит проделать большую работу по реализации красивого синтаксиса в стиле Ruby! Отрицательным является то, что ваш фильтр не является первоклассной функцией и, следовательно, не может быть использован повторно. Закатывающиеся застежки ...
Хорошая точка зрения. Один из способов повторно использовать тело цикла - преобразовать цикл в метод, который принимает запрос выбора в качестве параметра. Однако это, конечно, далеко не так удобно и мощно, как настоящие закрытия.
Java 8 (2014 г.) решает эту проблему, используя потоки и лямбды в одной строке кода:
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
Вот руководство.
Используйте Collection#removeIf, чтобы изменить коллекцию на месте. (Примечание: в этом случае предикат удалит объекты, удовлетворяющие этому предикату):
persons.removeIf(p -> p.getAge() <= 16);
лямбдаж позволяет фильтровать коллекции без написания циклов или внутренних классов:
List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
greaterThan(16)));
Вы можете представить что-нибудь более читабельное?
Заявление об ограничении ответственности: Я участник lambdaj
Приятно, но статический импорт запутывает происходящее. Для справки выберите / имеющий / включен статический импорт на ch.lambdaj.Lambda, больше чем org.hamcrest.Matchers
LambdaJ действительно привлекательный, но стоит отметить, что он подразумевает значительные накладные расходы (в среднем 2,6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis.
Видимо не работает на Android: groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5 sJ
Очень нравится этот пример LamdaJ ... похожий на встроенные в .NET лямбда-функции. А где пить в 16 лет? Нам следует подумать о добавлении ограничения локализации. :П
Бог! Я ненавижу эту утечку с Lambdaj, теперь, когда я использую Java 8, я ищу удаление каждого использования Lambdaj
Я попытался включить Lambdaj, но это было слишком сложно и было нечитаемо для людей, которые не знали Lambdaj. Хотя это только мой опыт.
Жаль, что он не может использовать перечисления. Я перешел на Apache Commons.
Этот ответ был бы даже лучше, если бы он также упомянул простейший метод (начиная с Java 8): Collection.removeIf
Я отредактировал ваш ответ, включив в него Collection#removeIf. Надеюсь, ты не против!
Интересно, почему верхняя половина не была дана в качестве нового ответа. Если бы это прошло сегодня через конвейер рецензирования, правка, вероятно, была бы отклонена. Сколько голосов за исходный вопрос и сколько за редактирование?
removeЕсли пример должен быть persons.removeIf(p -> p.getAge() <= 16);
Внимание: если вы используете лямбды внутри класса сущности Eclipselink (<2.7), это приведет к странным исключениям.
Java (8) наконец догнала dotNet Linq. Ура! # circa2007 en.wikipedia.org/wiki/Language_Integrated_Query
что это за перфорация? кто нибудь проверял?
persons.filter { it.age >= 16 }В C# это просто persons.Where(p => p.getAge() > 16).ToList(). Любая идея, почему Java требует шаблонов, таких как stream, Collectors.toList и т. д.?
Это, в сочетании с отсутствием реальных закрытий, является моей самой большой проблемой для Java. Честно говоря, большинство упомянутых выше методов довольно легко читаются и ДЕЙСТВИТЕЛЬНО эффективны; однако, проведя время с .Net, Erlang и т. д., понимание списков, интегрированное на уровне языка, делает все намного чище. Без дополнений на уровне языка Java не может быть такой же чистой, как многие другие языки в этой области.
Если производительность является огромной проблемой, можно использовать коллекции Google (или напишите свою собственную простую утилиту предикатов). Синтаксис Lambdaj более читабелен для некоторых людей, но не так эффективен.
А еще есть библиотека, которую я написал. Я проигнорирую любые вопросы относительно его эффективности (да, это так плохо) ... Да, я знаю, что он явно основан на отражении, и нет, я на самом деле его не использую, но он действительно работает:
LinkedList<Person> list = ......
LinkedList<Person> filtered =
Query.from(list).where(Condition.ensure("age", Op.GTE, 21));
ИЛИ ЖЕ
LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
Связь? Даже если ваша библиотека неэффективна или непригодна для использования по другим причинам, может быть интересно посмотреть, доступен ли исходный код.
Сделал репо публичным (net-machine.com/indefero/p/jdclib/source/tree/master). Вас интересует пакет выражений. В тестовом пакете есть тестер с примером использования. Я никогда особо не работал над интерфейсом строкового запроса, о котором говорилось выше (не хотелось писать настоящий синтаксический анализатор), поэтому явный интерфейс запроса в тестере - лучший вариант.
Я написал расширенный класс Iterable, который поддерживает применение функциональных алгоритмов без копирования содержимого коллекции.
Использование:
List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }
Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
public Boolean call(Integer n) throws FunctionalException
{
return n % 2 == 0;
}
})
for( int n : filtered )
{
System.out.println(n);
}
Приведенный выше код фактически выполнит
for( int n : myList )
{
if ( n % 2 == 0 )
{
System.out.println(n);
}
}
JFilter http://code.google.com/p/jfilter/ лучше всего подходит для ваших требований.
JFilter - это простая и высокопроизводительная библиотека с открытым исходным кодом для запроса коллекции компонентов Java.
Ключевая особенность
Вы должны отказаться от того, что являетесь автором (как я думаю).
Да, я являюсь автором этой библиотеки.
Используйте Механизм сбора запросов (CQEngine). На сегодняшний день это самый быстрый способ сделать это.
См. Также: Как вы запрашиваете коллекции объектов в Java (критерии / SQL-подобные)?
Давайте посмотрим, как отфильтровать встроенный список JDK и MutableList с помощью Коллекции Eclipse.
List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);
Если вы хотите отфильтровать числа меньше 3, вы ожидаете следующих результатов.
List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);
Вот как можно фильтровать, используя лямбда Java 8 в качестве Predicate.
Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));
Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));
Вот как вы можете фильтровать, используя анонимный внутренний класс как Predicate.
Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
public boolean accept(Integer each)
{
return each < 3;
}
};
Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));
Вот несколько альтернатив фильтрации списков JDK и Коллекции Eclipse MutableLists с использованием фабрики Предикаты.
Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
Вот версия, которая не выделяет объект для предиката, используя вместо этого фабрику Предикаты2 с методом selectWith, который принимает Predicate2.
Assert.assertEquals(
selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));
Иногда вам нужно отфильтровать отрицательное условие. Для этого в Eclipse Collections есть специальный метод, называемый reject.
Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));
Метод partition вернет две коллекции, содержащие элементы, выбранные и отклоненные Predicate.
PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());
PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());
Примечание: я являюсь приверженцем коллекций Eclipse.
Как бы вы включили removeIf в список или набор для примитивов?
API для removeIf был добавлен к примитивным коллекциям в EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collection s /…
Дождитесь Java 8:
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toList());
Ух ... это так многословно. Почему они не могли просто сделать: List <Person> result = personList.filter (p -> p.age> 30);
@KevinWong Я действительно получил пример из официального руководства, поэтому не знаю другого синтаксиса ...
Не сомневаюсь, что это официальный синтаксис. Я просто говорю, что это отстой.
Чтобы использовать фильтр непосредственно на Коллекция, вам необходимо использовать вызов removeIf: download.java.net/jdk8/docs/api/java/util/…
@KevinWong "многословный" в значительной степени описывает весь язык, я думаю. По крайней мере, они последовательны?
Почему бы не использовать Collectors.toList () в последней части?
personList.removeIf(p -> p.age < 30); Less verbose. Also, I've heard talk about starting to implement apis that accept and return Streams rather than Collections because Streams are very useful and fast but going to/from them is slow.
Начиная с раннего выпуска Java 8, вы могли попробовать что-то вроде:
Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);
Например, если у вас есть список целых чисел, и вы хотите отфильтровать числа, которые больше 10, а затем распечатать эти числа на консоли, вы можете сделать что-то вроде:
List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
Как насчет простой и понятной Java
List<Customer> list ...;
List<Customer> newList = new ArrayList<>();
for (Customer c : list){
if (c.getName().equals("dd")) newList.add(c);
}
Просто, читабельно и легко (и работает в Android!) Но если вы используете Java 8, вы можете сделать это одной милой строкой:
List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());
Обратите внимание, что toList () импортируется статически
Простое решение до Java8:
ArrayList<Item> filtered = new ArrayList<Item>();
for (Item item : items) if (condition(item)) filtered.add(item);
К сожалению, это решение не является полностью универсальным и выводит список, а не тип данной коллекции. Кроме того, использование библиотек или написания функций, которые обертывают этот код, кажется мне излишним, если только условие не является сложным, но тогда вы можете написать функцию для этого условия.
Закину в кольцо RxJava, который тоже есть на Android. RxJava не всегда может быть лучшим вариантом, но он даст вам больше гибкости, если вы захотите добавить больше преобразований в свою коллекцию или обработать ошибки при фильтрации.
Observable.from(Arrays.asList(1, 2, 3, 4, 5))
.filter(new Func1<Integer, Boolean>() {
public Boolean call(Integer i) {
return i % 2 != 0;
}
})
.subscribe(new Action1<Integer>() {
public void call(Integer i) {
System.out.println(i);
}
});
Выход:
1
3
5
Более подробную информацию о filter RxJava можно найти в здесь.
https://code.google.com/p/joquery/
Поддерживает разные возможности,
Данная коллекция,
Collection<Dto> testList = new ArrayList<>();
типа,
class Dto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
Фильтр
Java 7
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property("id").eq().value(1);
Collection<Dto> filtered = query.list();
Java 8
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property(Dto::getId)
.eq().value(1);
Collection<Dto> filtered = query.list();
Также,
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.property(Dto::getId).between().value(1).value(2)
.and()
.property(Dto::grtText).in().value(new string[]{"a","b"});
Сортировка (также доступно для Java 7)
Filter<Dto> query = CQ.<Dto>filter(testList)
.orderBy()
.property(Dto::getId)
.property(Dto::getName)
Collection<Dto> sorted = query.list();
Группировка (также доступно для Java 7)
GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
.group()
.groupBy(Dto::getId)
Collection<Grouping<Integer,Dto>> grouped = query.list();
Присоединяется (также доступно для Java 7)
Данный,
class LeftDto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
class RightDto
{
private int id;
private int leftId;
private String text;
public int getId()
{
return id;
}
public int getLeftId()
{
return leftId;
}
public int getText()
{
return text;
}
}
class JoinedDto
{
private int leftId;
private int rightId;
private String text;
public JoinedDto(int leftId,int rightId,String text)
{
this.leftId = leftId;
this.rightId = rightId;
this.text = text;
}
public int getLeftId()
{
return leftId;
}
public int getRightId()
{
return rightId;
}
public int getText()
{
return text;
}
}
Collection<LeftDto> leftList = new ArrayList<>();
Collection<RightDto> rightList = new ArrayList<>();
Может быть присоединен как,
Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
.<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
.on(LeftFyo::getId, RightDto::getLeftId)
.transformDirect(selection -> new JoinedDto(selection.getLeft().getText()
, selection.getLeft().getId()
, selection.getRight().getId())
)
.list();
Выражения
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.exec(s -> s.getId() + 1).eq().value(2);
Здесь есть действительно отличные ответы. Я хотел бы, чтобы все было как можно проще и читабельно:
public abstract class AbstractFilter<T> {
/**
* Method that returns whether an item is to be included or not.
* @param item an item from the given collection.
* @return true if this item is to be included in the collection, false in case it has to be removed.
*/
protected abstract boolean excludeItem(T item);
public void filter(Collection<T> collection) {
if (CollectionUtils.isNotEmpty(collection)) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (excludeItem(iterator.next())) {
iterator.remove();
}
}
}
}
}
Просто реализуйте правильный excludeItem для каждого фильтра. В конечном итоге у вас будут отдельные фильтры, точно так же, как у вас есть сортировщики в коллекциях ...
Мой ответ основан на этом от Кевина Вонга, здесь в качестве однострочного с использованием CollectionUtils из весна и выражения Java 8 лямбда.
CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);
Это так же лаконично и читабельно, как и любая альтернатива, которую я видел (без использования аспектно-ориентированных библиотек).
Spring CollectionUtils доступен с версии Spring 4.0.2.RELEASE, и помните, что вам нужен JDK 1.8 и уровень языка 8+.
Используя java 8, в частности lambda expression, вы можете сделать это просто, как в приведенном ниже примере:
myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())
где для каждого product в коллекции myProducts, если prod.price>10, добавить этот продукт в новый отфильтрованный список.
С гуавой:
Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);
Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
@Override
public boolean apply(Integer i) {
return i % 2 == 0;
}
});
System.out.println(collection); // Prints 1, 3, 5
Мне нужно было отфильтровать список в зависимости от значений, уже присутствующих в списке. Например, удалите все следующие значения, которые меньше текущего значения. {2 5 3 4 7 5} -> {2 5 7}. Или, например, чтобы удалить все дубликаты {3 5 4 2 3 5 6} -> {3 5 4 2 6}.
public class Filter {
public static <T> void List(List<T> list, Chooser<T> chooser) {
List<Integer> toBeRemoved = new ArrayList<>();
leftloop:
for (int right = 1; right < list.size(); ++right) {
for (int left = 0; left < right; ++left) {
if (toBeRemoved.contains(left)) {
continue;
}
Keep keep = chooser.choose(list.get(left), list.get(right));
switch (keep) {
case LEFT:
toBeRemoved.add(right);
continue leftloop;
case RIGHT:
toBeRemoved.add(left);
break;
case NONE:
toBeRemoved.add(left);
toBeRemoved.add(right);
continue leftloop;
}
}
}
Collections.sort(toBeRemoved, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i : toBeRemoved) {
if (i >= 0 && i < list.size()) {
list.remove(i);
}
}
}
public static <T> void List(List<T> list, Keeper<T> keeper) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
if (!keeper.keep(iterator.next())) {
iterator.remove();
}
}
}
public interface Keeper<E> {
boolean keep(E obj);
}
public interface Chooser<E> {
Keep choose(E left, E right);
}
public enum Keep {
LEFT, RIGHT, BOTH, NONE;
}
}
Это будет использоваться вот так.
List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
@Override
public Filter.Keep choose(String left, String right) {
return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
}
});
Поскольку Java 9Collectors.filtering включен:
public static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate,
Collector<? super T, A, R> downstream)
Таким образом, фильтрация должна быть:
collection.stream().collect(Collectors.filtering(predicate, collector))
Пример:
List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
.collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
В Java 8 вы можете напрямую использовать этот метод фильтрации, а затем сделать это.
List<String> lines = Arrays.asList("java", "pramod", "example");
List<String> result = lines.stream()
.filter(line -> !"pramod".equals(line))
.collect(Collectors.toList());
result.forEach(System.out::println);
это нормально, но не является универсальным и изменяет коллекцию на месте (нехорошо)