Який найкращий спосіб фільтрації колекції Java?


Відповіді:


699

Java 8 ( 2014 ) вирішує цю проблему за допомогою потоків і лямбда в одному рядку коду:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

Ось підручник .

Використовуйте Collection#removeIfдля зміни колекції на місці. (Примітка. У цьому випадку присудок видалить об'єкти, які задовольняють присудок):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj дозволяє фільтрувати колекції без написання циклів або внутрішніх класів:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Ви можете уявити щось більш читабельне?

Відмова: Я є учасником ламбдай


34
Приємно, але статичний імпорт заплутає те, що відбувається. Для довідки, вибрати / мати / включити статичний імпорт на ch.lambdaj.Lambda, більшийТаким є org.hamcrest.Matchers
MikePatel

11
LambdaJ - це справді сексуально, але варто зазначити, що він передбачає значні накладні витрати (у середньому 2,6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Док. Давлуз

7
Мабуть, не працює на Android: groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Моріц

7
Дійсно, як цей приклад LamdaJ ... схожий на .NET вбудовані функції Lambda. А де людина може пити у віці 16 років? Ми повинні розглянути можливість додавання обмеження для локалізації. : P
MAbraham1

3
RemoveIf приклад повинен бутиpersons.removeIf(p -> p.getAge() <= 16);
vim

223

Якщо припустити, що ви використовуєте Java 1.5 і не можете додавати Google Collections , я б зробив щось дуже схоже на те, що зробили хлопці 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);

Якщо виконання лінійної перевірки викликає занепокоєння, то я, можливо, захочу мати об’єкт домену, який має цільову колекцію. Об'єкт домену, який має цільову колекцію, повинен мати логіку фільтрації для методів, які ініціалізують, додають та встановлюють цільовий збірник.

ОНОВЛЕННЯ:

У класі утиліти (скажімо, предикат) я додав метод вибору з опцією значення за замовчуванням, коли предикат не повертає очікуваного значення, а також статичну властивість для парамм, які будуть використовуватися всередині нового 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.


27
Так, але я ненавиджу винаходити колесо, знову ж таки, повторно. Я вважаю за краще знайти якусь бібліотеку, яка працює, коли я хочу.
Кевін Вонг

2
Це не найкращий спосіб, якщо ви не хочете нової колекції. Використовуйте метафору ітератора фільтра, яка може ввести в нову колекцію, або це все, що вам потрібно.
Джош

@Nestor: у розумінні Scala фільтрування було б набагато простішим:val authorized = for (user <- users if user.isAuthorized) yield user
Алан,

Чи це змінює оригінальну колекцію чи створює абсолютно нову? Я спробував скористатися цим методом і записав обидві колекції (оригінал і той, що повернувся з методу), вони однакові. @Alan
Rohan

1
@ Рохан, це не призначене для мутації оригінальної колекції. Зауважте, що вищезгаданий збірник результатів нещодавно побудований, а метод фільтрації додає до колекції результатів лише у тому випадку, якщо застосовується предикат.
Алан

92

Використовуйте CollectionUtils.filter (Колекція, предикат) від Apache Commons.


3
це нормально, але це не є загальним, і змінює колекцію на місці (не приємно)
Кевін Вонг,

2
У CollectionUtils існують інші методи фільтрування, які не змінюють оригінальну колекцію.
skaffman

42
Зокрема, метод, який не змінює колекцію на місці, - org.apache.commons.collections.CollectionUtils # select (Колекція, предикат)
Eero

5
У Commons Collections v4 зараз використовується Generics.
Джастін Емері

1
Цей метод слід застосовувати з обережністю, оскільки він покладається (принаймні на реалізацію commons-collection-3.2.1) методу iterator.remove (), який не є обов'язковим для колекцій, тому замість фільтрування, скажімо, масиву, ви можете отримати UnsupportedOperationException.
user2417480

67

"Найкращий" спосіб - це занадто широкий запит. Це "найкоротше"? "Найшвидший"? "Читабельний"? Фільтр на місці чи в іншій колекції?

Найпростіший (але не найбільш читаний) спосіб - це повторити його та використовувати метод 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 (), щоб дізнатися, чи повинен зберігатися екземпляр у колекції.

Я дійсно не бачу виправдання для залучення сторонніх бібліотек саме для цього завдання.


6
Мій голос іде за це: він просто працює, без зовнішніх бібліотек. Я ніколи не усвідомлював, що інстанціювання ітератора може бути корисним порівняно із використанням синтаксису для кожного, або ви можете видалити елементи зі списку без ConcurrentModificationException чи чогось подібного. :)
ZeroOne

1
Я думаю, що це найкращий спосіб використовувати стандартний Java lib без копіювання. Для 1.8 це буде stream()функцією, але не всі отримують можливість грати з найновішими іграшками: P
Populus

Чи це також змінює оригінальну колекцію? @ZeroOne
Рохан

Так, звичайно, так, @Rohan. Спробуйте, якщо ви не повірите. ;)
ZeroOne

Ха-ха! Але я хочу зберегти свою оригінальну колекцію. Чи можете ви запропонувати спосіб це зробити, не додаючи зовнішню вкладку? @ZeroOne
Рохан

62

Розгляньте колекції Google для оновленої структури колекцій, яка підтримує дженерики.

ОНОВЛЕННЯ : Бібліотека колекцій Google зараз застаріла. Слід скористатись останньою версією Guava . Він досі має все ті ж розширення до системи колекцій, включаючи механізм фільтрації на основі присудка.


Так, я знав про колекційну колекцію Google. Версія, яку я використовував, у ній не було Collections2. Я додав нову відповідь на це питання, в якому перераховано конкретний метод.
Кевін Вонг

7
Кевін, Iterables.filter () і Iterators.filter () були там з самого початку, і зазвичай це все, що вам потрібно.
Кевін Бурліон

28

Зачекайте на 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());

13
Тьфу ... це так багатослівно. Чому вони не могли просто зробити: Список <Person> result = personList.filter (p -> p.age> 30);
Кевін Вонг

8
Щоб використовувати фільтр безпосередньо в колекції, вам потрібно скористатися функцією RemoveIf call: download.java.net/jdk8/docs/api/java/util/…
gavenkoa

6
@KevinWong "багатослівний" в значній мірі описує усю мову, яку я думаю. Принаймні вони послідовні?
Rogue

5
Чому б не використовувати Collectors.toList () в останній частині?
Нестор Ернандес Лолі

3
Ось посилання gavenkoa за умови, що не 404. personList.removeIf(p -> p.age < 30);Менше багатослівного. Крім того, я чув розмови про початок впровадження apis, які приймають і повертають Streams, а не Collections, тому що Streams дуже корисні і швидкі, але перехід до / з них повільний.
Капітан Людина

11

З самого раннього випуску 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);

11

Я кину 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

Детальніше про RxJava filterможна прочитати тут .


7

Установка:

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

2
Чудово, але я віддаю перевагу реалізації Alan, тому що ви отримуєте копію колекції замість того, щоб змінювати її. Більше того, код Алана є безпечним для потоків, а ваш - ні.
marcospereira

7

Як щодо якоїсь простої та прямої 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 () статично імпортується



7

Давайте розглянемо, як фільтрувати вбудований список JDK та MutableList за допомогою Eclipse Collections .

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 Collections MutableLists за допомогою фабрики Predicate .

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Ось версія, яка не виділяє об’єкт для предиката, використовуючи замість цього заводу метод Predicate2, а не selectWithметод, який використовує a Predicate2.

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

Іноді потрібно фільтрувати за негативним станом. У колекціях Eclipse існує спеціальний метод для того, що називається 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.


1
Як би ви зробили removeIfсписок у списку чи наборі для примітивів?
Vivek Rao

API для deleteIf був доданий до примітивних колекцій у EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/…
Дональд Рааб

5

З DSL ForEach ви можете писати

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

Враховуючи колекцію [Швидкий, коричневий, лисиця, стрибки, над, ледачий, собака], це призводить до [швидкого, коричневого, стрибків, лінивого], тобто всіх рядків довше трьох символів.

Усі стилі ітерації, що підтримуються DSL ForEach, є

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Для отримання детальної інформації див. Https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach


Це досить розумно! Багато роботи, щоб реалізувати приємний синтаксис Ruby-ish! Негативним є те, що ваш фільтр не є першокласною функцією, і тому його неможливо повторно використовувати.
Ролик

Гарна думка. Один із способів повторного використання тіла циклу - це рефакторинг циклу на метод, який приймає запит вибору як параметр. Це, однак, далеко не так зручно і потужно, як справжні закриття.
акун


5

Оскільки java 9 Collectors.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()));

3

Це в поєднанні з відсутністю реальних закриттів є моїм найбільшим захопленням для Java. Чесно кажучи, більшість згаданих вище методів досить легко читати і дійсно ефективні; однак, витративши час на .Net, Erlang тощо ... інтегрованість списку, інтегрована на мовному рівні, робить все набагато чистішим. Без доповнень на мовному рівні, Java просто не може бути такою ж чистою, як і багато інших мов у цій області.

Якщо продуктивність викликає велике занепокоєння, колекція Google - це шлях (або написати власну просту утиліту предикатів). Синтаксис лямбдатів для деяких людей легше читати, але він не настільки ефективний.

А тут є бібліотека, яку я написав. Я проігнорую будь-які питання щодо його ефективності (так, це так погано) ...... Так, я знаю, що його чітко відображається, і ні, я насправді не використовую, але це працює:

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

Посилання? Навіть якщо ваша бібліотека є неефективною або іншою мірою непридатною, може бути цікаво подивитися, чи джерело доступне.
MatrixFrog

Оголосив репо-публіку ( net-machine.com/indefero/p/jdclib/source/tree/master ). Вас цікавить пакет виразів. Тестовий пакет має тестер із прикладом використання. Я ніколи не робив багато роботи над інтерфейсом рядкового запиту, про який було сказано вище (не відчував, як писати справжній аналізатор), тому явний інтерфейс запитів у тестері - це шлях.
jdc0589

2

JFilter http://code.google.com/p/jfilter/ найкраще відповідає вашим вимогам.

JFilter - це проста і високопродуктивна бібліотека з відкритим кодом для запиту колекції Java-бобів.

Ключові особливості

  • Підтримка властивостей колекції (java.util.Collection, java.util.Map та Array).
  • Підтримка колекції всередині колекції будь-якої глибини.
  • Підтримка внутрішніх запитів.
  • Підтримка параметризованих запитів.
  • Може фільтрувати 1 мільйон записів за кілька 100 мс.
  • Фільтр (запит) задається у простому форматі json, він подібний до запитів Mangodb. Далі наведено кілька прикладів.
  • {"id": {"$ le": "10"}
    • де властивість id об'єкта менше, ніж дорівнює 10.
  • {"id": {"$ in": ["0", "100"]}}
    • де властивість id об'єкта дорівнює 0 або 100.
  • {"lineItems": {"lineAmount": "1"}}
    • де властивість збирання lineItems параметризованого типу має lineAmount дорівнює 1.
  • {"$ and": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
    • де властивість id дорівнює 0, а властивість billingAddress.city - DEL.
  • {"lineItems": {"податки": {"key": {"код": "GST"}, "value": {"$ gt": "1.01"}}}}
    • де властивість збирання lineItems параметризованого типу, яка має властивість типу картки податків, тип параметру має тип коду, рівний значенню GST, що перевищує 1,01.
  • {'$ або': [{'код': '10'}, {'skus': {'$ і': [{'ціна': {'$ in': ['20', '40']} }, {'code': 'RedApple'}]}}]}
    • Виберіть усі продукти, де код товару 10 або sku ціна в 20 і 40, а код sku - "RedApple".

1
Вам слід відмовитися від того, що ви є автором (як я думаю, це так).
assylias

Так, я автор цієї бібліотеки.
Камран Алі Хан

2

Я написав розширений клас 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);
    }
}


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

Просто введіть відповідний исключенный шаблон для кожного фільтра. У вас з’являться окремі фільтри саме так, як у вас є сортувальники по колекціях ...
Лоуренс

1

Просте рішення перед Java8:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

На жаль, це рішення не є повністю загальним, виводить список, а не тип даної колекції. Крім того, залучення до бібліотек або функцій запису, які обробляють цей код, здається мені надмірним, якщо умова не є складною, але тоді ви можете написати функцію для умови.


1

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

1

Моя відповідь ґрунтується на тому , що від Кевіна Вонга, ось як однострочнікі з використанням CollectionUtilsвід пружини і Java 8 лямбда - вираження.

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Це настільки стисло і читабельно, як і будь-яка альтернатива, яку я бачив (без використання бібліотек, що базуються на аспектах)

Spring CollectionUtils доступний з весняної версії 4.0.2.RELEASE, і пам’ятайте, що вам потрібні JDK 1.8 та рівень мови 8+.


1

Використання java 8, в зокрема lambda expression, ви можете зробити це просто , як на прикладі нижче:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

де для кожної productвнутрішньої myProductsколекції, якщо prod.price>10, тоді додайте цей продукт до нового відфільтрованого списку.


1

Мені потрібно було фільтрувати список залежно від значень, вже наявних у списку. Наприклад, видаліть усі наступні значення, менші за поточне значення. {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;
    }
});

0

З Гуавою:

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

0

У 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); 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.