I am relatively new in Java 8 and lambda expressions as well as Stream
, i can calculate factorial using for
loop or recursion. But is there a way to use IntStream
to calculate factorial of a number ? I am fine even with factorial in integer range.
I read through IntStream
docs here, http://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html and i can see so many methods but not sure which one I can use to calculate factorial.
for example, there is rang
method that says,
range(int startInclusive, int endExclusive) Returns a sequential ordered IntStream from startInclusive (inclusive) to endExclusive (exclusive) by an incremental step of 1.
so I can use it to provide the range of numbers to IntStream to be multiplied to calculate factorial.
number = 5;
IntStream.range(1, number)
but how to multiply those numbers to get the factorial ?
You can use IntStream::reduce for this job,
int number = 5;
IntStream.rangeClosed(2, number).reduce(1, (x, y) -> x * y)
To get a stream of all infinite factorials, you can do:
class Pair{
final int num;
final int value;
Pair(int num, int value) {
this.num = num;
this.value = value;
}
}
Stream<Pair> allFactorials = Stream.iterate(new Pair(1,1),
x -> new Pair(x.num+1, x.value * (x.num+1)));
allFactorials
is a stream of factorials of number starting from 1 to ..... To get factorials of 1 to 10:
allFactorials.limit(10).forEach(x -> System.out.print(x.value+", "));
It prints: 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800,
Now say you only wish to have a factorial of a particular number then do:
allFactorials.limit(number).reduce((previous, current) -> current).get()
The best part is that you dont recompute again for new numbers but build on history.
With LongStream.range() you can calculate factorial for number less 20. If you need calculate for larger number create stream with BigInteger:
public BigInteger factorial(int number) {
if (number < 20) {
return BigInteger.valueOf(
LongStream.range(1, number + 1).reduce((previous, current) -> previous * current).getAsLong()
);
} else {
BigInteger result = factorial(19);
return result.multiply(Stream.iterate(BigInteger.valueOf(20), i -> i.add(BigInteger.ONE)).limit(number - 19)
.reduce((previous, current) -> previous.multiply(current)).get()
);
}
}
We can solve the question with AtomicInteger like this:
int num = 5;
AtomicInteger sum = new AtomicInteger(1);
IntStream.rangeClosed(2, num).forEach(i -> {
sum.updateAndGet(v -> v * i);
if (i == num) {
System.out.println(sum.get());
}
});
I think we can change the main condition to: 1,v v-1,s t with the function reduce. Maybe we can filter before we did the main rule
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.