2014-12-03 2 views
6

Есть ли способ (метод, лямбда или элегантная конструкция), чтобы найти элемент в списке на основе данного компаратора?Список :: содержит с компаратором

Я написал метод, как это:

private static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) { 
    return list.stream() 
      .anyMatch(listItem -> comparator.compare(listItem, item) == 0 
      ); 
} 

Но я ищу, чтобы заменить его чем-то, что было бы более элегантно.

Я не хочу, чтобы добавить какую-либо зависимость, поэтому не гуава, «обыкновенные» и т.д. Я действительно искал довольно способ сделать это в Java 8.

EDIT: Some пример того, что Я бы рассмотреть более изящным (здесь является использование кода):

// sadly, this method doesn't exist 
// nor is there a static one in Collections 
// but maybe you can think of another way? 
if (list.containsSame(item, comparator)) { 
    // ... 
} 
+4

Ну, как код, который вы пишете, удовлетворяет вас? Это выглядит просто отлично (хотя в сигнатуре я бы поставил вместо этого «Компаратор ») – fge

+0

Я чувствую, что это можно улучшить с помощью умного использования платформы или языка. – ymajoros

+1

, используя потоки со своими собственными компараторами, - это в значительной степени то, что большинство людей назвали бы «умным использованием фреймворка». То же самое самое «красивое» из-за лямбда. Чего еще можно хотеть? – specializt

ответ

1

Не уверен, является ли то, что вы хотите, но одна возможность заключается в том, чтобы создать свой собственный интерфейс расширения Stream и обеспечивают метод, который вы хотите (ПРИМЕЧАНИЕ: UNTESTED):

public interface MyStream<R> 
    extends Stream<R> 
{ 
    // Yay! Static methods in interfaces! 
    public static <E> MyStream<E> of(final Collection<E> collection) 
    { 
     return new MyStreamImpl<E>(collection); 
    } 

    // Yay! Default methods in interfaces! 
    default boolean containsAny(R item, Comparator<? super R> comparator) 
    { 
     return anyMatch(e -> comparator.compare(item, e) == 0); 
    } 
} 

public class MyStreamImpl<R> 
    implements MyStream<R> 
{ 
    private final Stream<R> stream; 

    public MyStreamImpl(final Collection<R> collection) 
    { 
     this.stream = Objects.requireNonNull(collection.stream()); 
    } 

    // delegate all other operations to stream 
} 

Тогда вы могли бы использовать:

MyStream.of(someList).containsAny(item, comparator); 

(но это много кода для не так много, на самом деле)

+0

Это означает, что в этом потоке вместо этого используется только вызов метода. Я хочу избавиться от моего дополнительного кода, который я бы хотел заменить чем-то более простым. – ymajoros

1

Почему вы хотите, чтобы создать дополнительную функцию в первую очередь? Просто звоните каждый раз, когда работает поток.

Если вы настаиваете, вместо Comparator вы можете использовать BiPredicate.

Например.

BiPredicate<Integer,Integer> greaterThan = (i,s) -> i > s; 

И изменить функцию содержать что-то вроде

private static <T> boolean containsp(List<T> list, T item, BiPredicate<? super T,? super T> biPredicate)  { 
    return list.stream().filter(l-> biPredicate.test(l,item)).findFirst().isPresent(); 
} 

Я не знаю, если это более элегантно, но это, кажется, работает.

+0

Я не хочу создавать дополнительную функцию. Я бы скорее избавился от него. – ymajoros

+0

Просто используйте 'list.stream(). AnyMatch (listItem -> * и поместите здесь ваше выражение *);'. Где ответы не отвечают вашим потребностям. –

+0

Это выражение повторяется в 5 разных местах моего кода. Я хочу что-то многоразовое, поэтому у меня есть этот метод.На самом деле я не настаиваю на этом методе, я думаю, что будет проще с стандартными API Java. – ymajoros

5

Насколько я знаю, нет встроенных функций, непосредственно связанных с этой задачей. Поэтому, поскольку вы не можете избежать создания методов утилиты (если вы хотите уменьшить дублирование кода), стоит подумать, какой метод полезности может быть полезен и в других сценариях.

E.g. если бы это был мой проект, я знал, что почти всегда есть способы применения частичной функции летающих вокруг, как:

public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) { 
    return u -> f.apply(t, u); 
} 

Используя этот существующий метод, решение может выглядеть следующим образом:

static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) { 
    return list.stream().map(bind(comparator::compare, item)) 
         .anyMatch(Predicate.isEqual(0)); 
} 

Но это не обязательно лучшее решение.

Другой подход мог бы иметь способ для преобразования Comparator в равенство BiPredicate и служебный метод для частичного применения BiPredicate:

public static <T> BiPredicate<T,T> match(Comparator<T> f) { 
    return (a,b)->f.compare(a, b)==0; 
} 
public static <T,U> Predicate<U> bind(BiPredicate<T,U> f, T t) { 
    return u -> f.test(t, u); 
} 

Тогда метод contains становится таким же простым, как

static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) { 
    return list.stream().anyMatch(bind(match(comparator), item)); 
} 

Но это лишь упрощение, если методы утилиты можно использовать и в других местах вашего проекта. С другой стороны, они имеют такой общий характер, что подобные методы могут быть добавлены как методы default к функциональным интерфейсам в последующей версии Java. В этом случае ваш код с использованием таких методов утилиты подготовлен для перехода на эту более новую версию.

0

Вы можете использовать следующие методы: from the commons-collections version 4+

  • IterableUtils.contains(Iterable<? extends E> iterable, E object, Equator<? super E> equator) - Проверяет, является ли объект, содержащиеся в данной итерации.
  • IterableUtils.matchesAny(Iterable<E> iterable, Predicate<? super E> predicate) - Ответы истины, если предикат верен для любого элемента итерабельного.
Смежные вопросы