列表::包含比较器

2022-09-04 20:39:03

有没有办法(方法,lambda或优雅的构造)在基于给定比较器的列表中找到元素?

我写了一个这样的方法:

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)) {
    // ...
}

答案 1

据我所知,没有直接解决此任务的内置功能。因此,由于您无法避免创建实用程序方法(如果您想减少代码重复),因此值得考虑哪种实用程序方法在其他情况下也很有用。

例如,如果这是我的项目,我知道几乎总是有部分函数应用的方法飞来飞去,比如:

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

但这不一定是最好的解决方案。

另一种方法可能是使用一个将 a 转换为相等的方法,以及一个用于部分应用的效用方法:ComparatorBiPredicateBiPredicate

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发行版中的函数接口中。在这种情况下,使用此类实用工具方法的代码已准备好迁移到该较新版本。default


答案 2

您可以使用共享资源集合版本 4+ 中的下一个方法:

  • IterableUtils.contains(Iterable<? extends E> iterable, E object, Equator<? super E> equator)- 检查对象是否包含在给定的可迭代对象中。
  • IterableUtils.matchesAny(Iterable<E> iterable, Predicate<? super E> predicate)- 如果谓词对于可迭代的任何元素都为真,则回答 true。

推荐