I'm looking for a simple and elegant one line way to check if the int
result of an expression is contained in a list of integers.
Example: Check if foo(…)
produces either 1, 2 or 7.
Constraints:
foo(…)
should only be evaluated once. final
variables may be used, including lambdas. But foo(…)
(and its result) and the list of int
s should not be part of this variables. To illustrate: java.util.Arrays.asList(1, 2, 7).contains(foo(…))
meets all criteria except it requires boxing.
Note: I'm only interested what possible solutions could look like. In practice I would probably use my illustration example, ArrayUtils.contains(…)
from Commons Lang or Ints.contains(…)
from Guava .
I'll add three possible solutions later if they don't come up anyway. But I wonder if there are any more elegant solutions, as mine are not really that elegant and I'm a bit surprised Java does not seem to provide something like this out of the box.
二分查找呢?
Arrays.binarySearch(new int[] {1, 2, 7}, foo(...)) >= 0
You could filter out the results using a lambda instead, if you're guaranteed a List
. If you're not, you can wrap it inside of a Arrays#asList
operation.
This will short-circuit on the first value that evaluates to true
.
List<Integer> intList = Arrays.asList(foo());
boolean exists = intList.stream().anyMatch(x -> x == 1 || x == 2 || x == 7);
There is going to be a level of boxing due to the way that the stream has to be created; if you really want to avoid it for whatever reason, you've got a couple of options.
Create an int[]
, then create an IntStream
from it:
boolean exists = Arrays.stream(new int[](foo())) .anyMatch(x -> x == 1 || x == 2 || x == 7);
Convert to an IntStream
as an intermediate step (does involve boxing to a degree)
boolean exists = intList.stream() .mapToInt(Integer::intValue) .anyMatch(x -> x == 1 || x == 2 || x == 7);
As promised in the question, here are my solutions:
Besides the one of Tagir Valeev using Arrays.binarySearch(…)
I did some variations using lambdas:
Building an IntPredicate
by joining multiple predicates:
final IntFunction<IntPredicate> intEquals = v1 -> v2 -> v1 == v2; intEquals.apply(1).or(intEquals.apply(2)).or(intEquals.apply(7)).test(foo(…));
This makes adding a new number to the list very verbose.
First building a IntPredicate
avoids the need to encapsulate the result of foo(…)
somehow to prevent evaluating it more than once.
This one does the same as the previous solution, but adding a new number is less verbose (at the cost of a more complex lambda):
final IntFunction<IntPredicate> intEquals = v1 -> v2 -> v1 == v2; final Function<Function<IntStream.Builder, IntStream.Builder>, IntPredicate> pred = c -> c.apply(IntStream.builder()).build().mapToObj(intEquals).reduce(IntPredicate::or).get(); pred.apply(b -> b.add(1).add(2).add(7)).test(foo(…));
Building a IntPredicate
from an array:
final Function<int[], IntPredicate> oneOf = ints -> testInt -> IntStream.of(ints).anyMatch(arrayInt -> testInt == arrayInt); oneOf.apply(new int[] { 1, 2, 7 }).test(foo(…));
This is in principe similar to the answer provided by Makoto but the other way around (he put the single value in front of the stream).
Using IntStream.of(…)
instead of writing new int[] {…}
:
final Function<IntStream, IntPredicate> oneOf = ints -> testInt -> ints.anyMatch(streamInt -> testInt == streamInt); oneOf.apply(IntStream.of(1, 2, 7)).test(foo(…));
This could be even shortened using a static import of IntStream.of
.
With the use of BiPredicate
the call can be made even shorter:
final IntFunction<IntPredicate> intEquals = v1 -> v2 -> v1 == v2; final BiPredicate<IntStream, IntSupplier> oneOf = (list, value) -> list.anyMatch(intEquals.apply(value.getAsInt())); oneOf.test(of(1, 2, 7), () -> foo(…));
Here a IntSupplier
is used to avoid the recalculation of foo(…)
.
So the bottom line for me is: Java does not provide a concise, ready to use function that meets the requirements. The binarySearch
method works but requires a sorted list of integers and does not express the intend very well. The lambda variants are all a bit complex. So apparently I'll have to drop some of the constraints :-P
But it was an interesting challenge to look at, in my opinion…
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.