2014-12-03 55 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。