2014-12-03 14 views
6

Czy istnieje sposób (metoda, lambda lub elegancki konstrukt), aby znaleźć element na liście na podstawie danego komparatora?Lista :: zawiera kompilator

napisałem metodę tak:

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

ale szukam go zastąpić czymś, co byłoby bardziej elegancki.

Nie chcę dodawać żadnych zależności, więc nie guawy, „commons” itd ja naprawdę szukam ładnej sposób to zrobić w Javie 8.

EDIT: Niektóre przykład co Pomyślę o bardziej elegancki (tutaj jest za pomocą kodu):

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

Cóż, czy kod, który piszesz, nie zadowala? Wygląda dobrze (chociaż w podpisie dostarczyłbym 'Komparator ' zamiast) – fge

+0

Mam wrażenie, że można go poprawić dzięki inteligentnemu wykorzystaniu platformy lub języka. – ymajoros

+1

używanie strumieni z własnymi komparatorami jest prawie tym, co większość ludzi nazwałaby "inteligentnym wykorzystaniem frameworka". To także najbardziej "ładny" sposób z powodu lambda. Czego chcieć więcej? – specializt

Odpowiedz

1

Nie wiem, czy to jest to, co chcesz, ale jedna z możliwości jest tworzenie własnego interfejsu rozszerzenie Stream i zapewnić metodę chcesz (uwaga: NIEPRAWIDŁOWO):

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 
} 

Następnie można użyć:

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

(ale to dużo kodu nie za dużo, naprawdę)

+0

Oznacza to zawijanie strumienia w tym miejscu zamiast wywoływania metody. Chcę pozbyć się dodatkowego kodu, który chciałbym zastąpić czymś łatwiejszym. – ymajoros

1

Dlaczego chcesz utworzyć dodatkową funkcję w pierwszej kolejności? Po prostu dzwoń za każdym razem, gdy działa strumień.

Jeśli nalegasz, zamiast Comparator możesz użyć BiPredicate.

Na przykład.

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

I zmienić funkcję zawierać coś jak

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

ja nie wiem, czy jest to bardziej eleganckie, ale wydaje się działać.

+0

Nie chcę tworzyć dodatkowej funkcji. Wolałbym się go pozbyć. – ymajoros

+0

Po prostu użyj 'list.stream(). AnyMatch (listItem -> * i wstaw tutaj swoje wyrażenie *);'. Gdzie odpowiedzi nie spełniają twoich potrzeb. –

+0

To wyrażenie jest powtarzane w 5 różnych miejscach w moim kodzie. Chcę coś do ponownego użycia, dlatego mam tę metodę.Tak naprawdę nie nalegam na tę metodę, myślę, że będzie prostszy sposób ze standardowymi API Java. – ymajoros

5

O ile mi wiadomo, nie ma wbudowanych funkcji bezpośrednio realizujących to zadanie. Ponieważ nie można uniknąć tworzenia metod użytkowych (jeśli chcesz ograniczyć powielanie kodu), warto zastanowić się, jaki rodzaj narzędzia może być użyteczny również w innych sytuacjach.

E.g. gdyby to był mój projekt Wiedziałem, że prawie zawsze są sposoby częściowego zastosowania funkcji latające dookoła, jak:

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

Wykorzystując tę ​​istniejącą metodę, to rozwiązanie może wyglądać tak:

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

Ale to nie jest koniecznie najlepsze rozwiązanie.

Innym rozwiązaniem mogłoby być dysponowanie sposobem do konwersji Comparator na równi BiPredicate i sposób użytkowego do częściowego stosowania 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); 
} 

wówczas sposób contains staje się tak łatwe, jak

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

Jest to jednak tylko uproszczenie, jeśli metody użytkowe można wykorzystać również w innych miejscach projektu. Z drugiej strony mają one ogólny charakter, że podobne metody mogą zostać dodane jako metody do interfejsów funkcji w kolejnej wersji Java. W takim przypadku Twój kod wykorzystujący takie metody narzędziowe jest przygotowany do migracji do nowszej wersji.

0

Można użyć kolejnych metod from the commons-collections version 4+:

  • IterableUtils.contains(Iterable<? extends E> iterable, E object, Equator<? super E> equator) - Sprawdza, czy obiekt jest zawarty w dany iterable.
  • IterableUtils.matchesAny(Iterable<E> iterable, Predicate<? super E> predicate) - Odpowiada prawdzie, jeśli predykat jest prawdziwy dla dowolnego elementu elementu iteracji.
Powiązane problemy