Is there any way (method, lambda, or elegant construct) to find an element in a list based on a given comparator?
I wrote a method like this:
private static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) {
return list.stream()
.anyMatch(listItem -> comparator.compare(listItem, item) == 0
);
}
But I'm looking to replace it with something that would be more elegant.
I don't want to add any dependency, so no Guava, "commons", etc. I'm really looking for a pretty way to do this in Java 8.
EDIT: Some example of what I'd consider more elegant (here is the using code):
// 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)) {
// ...
}
As far as I know, there is no built-in functionality directly addressing this task. So since you can’t avoid creating utility methods (if you want reduce code duplication), it’s worth thinking about which kind of utility method could be useful in other scenarios as well.
E.g. if it was my project I knew there are almost always methods for partial function application flying around, like:
public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) {
return u -> f.apply(t, u);
}
Utilizing this existing method, a solution could look like:
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));
}
But this is not necessarily the best solution.
Another approach could be to have a method for converting a Comparator
into an equality BiPredicate
and a utility method for partial application of a 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);
}
Then the contains
method becomes as simple as
static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) {
return list.stream().anyMatch(bind(match(comparator), item));
}
But this is only a simplification if the utility methods can be used at other places of your project as well. On the other hand, they are of such a general nature that similar methods might be added as default
methods to the function interfaces in a subsequent Java release. In this case your code using such utility methods is prepared for migration to that newer version.
You can use the next methods from the commons-collections
version 4+:
IterableUtils.contains(Iterable<? extends E> iterable, E object, Equator<? super E> equator)
- Checks if the object is contained in the given iterable.IterableUtils.matchesAny(Iterable<E> iterable, Predicate<? super E> predicate)
- Answers true if a predicate is true for any element of the iterable.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With