2014-12-03 80 views
6

有什麼方法(方法,lambda或優雅的結構)在列表中找到基於給定比較器的元素?List ::包含比較器

我寫了這樣的方法:

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

編輯:一些例子是什麼我會考慮更優雅(這裏是使用代碼):

// 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 2014-12-03 10:51:35

+0

我覺得可以通過智能使用平臺或語言來改善它。 – ymajoros 2014-12-03 11:31:05

+1

與您自己的比較器一起使用流是幾乎所有人都稱之爲「框架的巧妙使用」。由於lambda,這也是最「漂亮」的方式。你還能想要什麼? – specializt 2014-12-03 11:37:03

回答

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 2014-12-03 12:48:20

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 2014-12-03 12:48:42

+0

剛剛使用'list.stream()。anyMatch(listItem - > *並放置在這裏表達式*);'。答案不能滿足你的需求。 – 2014-12-03 13:44:46

+0

這個表達式在我的代碼中的5個不同的地方重複。我想要一些可重用的東西,這就是爲什麼我有這種方法。我實際上並不堅持這種方法,我想用標準的Java API會有一個更簡單的方法。 – ymajoros 2014-12-03 13:46:29

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

但是,這只是一種簡化,如果實用方法也可以在項目的其他地方使用。另一方面,它們具有如此普遍的性質,以致在隨後的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) - 如果謂詞對於迭代器的任何元素都爲真,則爲true。