calculating factorial using Java 8 IntStream? - java

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,vv-1,st with the function reduce.
Maybe we can filter before we did the main rule

Related

saving many intgers into 1 integer

I am trying to save many natural numbers that are smaller than m into 1 natural number n.
I need a function to read i'th number from n.
In python I can do it like:
def read(n,m,i):#reads a number on index i from n.
return n//m**i%m
def save(numbers_to_save, m=None):#saves natural numbers, that are smaller than m to n.
if m is None:
m=max(numbers_to_save)+1
n=0
for i_number in range(len(numbers_to_save)):
n+=m**i_number*numbers_to_save[i_number]
return n
numbers_to_save=[12,54,3,7,23,8,9,3,72,3]
i_max=len(numbers_to_save)
m=max(numbers_to_save)+1
n=save(numbers_to_save,m)
del numbers_to_save
for i in range(i_max):
print(read(n,m,i),end=",")
But how to do it effectively in java reading n only byte per byte? n is bigger than maximum value of long, so I can not use long to save n.
To translate this code to Java, you would need to use BigInteger class.
It works similarly to Python's "infinite" size integers, but with two key differences:
It is immutable, which means every time you change it, the result is a new object you must store in place of the old one.
You can't use regular operators (+, -, *, +) on it directly, but instead you must use the instance methods such as add or pow.
Here is an example of how your read function will look in Java:
int read(BigInteger n, BigInteger m, int i) {
return n.divide(m.pow(i)).mod(m).intValue();
}
Note, that for simplicity, this code assumes that both i and m will be smaller than MAX_INT.
It is possible to make both of them BigInteger as well to allow them to be of any size.
A long can be used for that specific given numbers (since m**count < Long.MAX_VALUE).
import static java.lang.Math.*;
public static long save(int m, int... numbers) {
long result = 0;
long mult = 1;
for (var num : numbers) {
if (num <0 || num >= m) throw new IllegalArgumentException("invalid: " + num);
result = addExact(result, multiplyExact(mult, num));
mult = multiplyExact(mult, m);
}
return result;
}
public static int read(long compressed, int m, int i) {
return (int) (compressed / (long)pow(m, i) % m);
}
private static void test() {
int[] numbers = { 12, 54, 3, 7, 23, 8, 9, 3, 72, 3};
int m = Arrays.stream(numbers).max().orElseThrow() + 1;
long compressed = save(m, numbers);
for (var i = 0; i < numbers.length; i++) {
int val = read(compressed, m, i);
if (val == numbers[i])
System.out.println(val);
else
System.err.printf("%d != %d # %d%n", val, numbers[i], i);
}
}
I am a bit lazy, so I used the Math methods addExactly and multiplyExact that throw an Exception in case of overflow. Alternative: check if long can save that count of numbers given m at start of method and use
result += mult * num;
mult *= m;
instead in the loop.
Use BigInteger as posted in this answer), if more space is needed.
this code also works with int to compress less, smaller values

Get missing number from int array with Java streams

I have following array,
int [] a = {5,3,10,8,4,2,9,6};
I am trying get the missing number from tha array,
private static int getMissingNumber(int[] a) {
int expectedSum = IntStream.rangeClosed(1, 10)
.reduce(0, Integer::sum);
int actualSum = Arrays.stream(a).reduce(0, Integer::sum);
return expectedSum-actualSum;
}
But is getting 8 instead of 7. What am I missing here?
You minimal value is 2 so should be the start of the range IntStream.rangeClosed(2, 10)
Also you can directly call .sum() on IntStream
private static int getMissingNumber(int[] a) {
return IntStream.rangeClosed(2, 10).sum() - Arrays.stream(a).sum();
}
The sum of the numbers from 1 to 10 Is 10 * (10+1) / 2 = 55. You are missing 1 and 7, so the sum of the missing numbers is 8. Looks right to me.
You need to use 2 instead of 1 ,
IntStream.rangeClosed(2, 10)
You can also find min and max elements in the array using summaryStatistics(),
private static int getMissingNumber(int[] a) {
IntSummaryStatistics summaryStatistics = Arrays.stream(a).summaryStatistics();
int expectedSum = IntStream.rangeClosed(summaryStatistics.getMin(), summaryStatistics.getMax())
.sum();
int actualSum = (int) summaryStatistics.getSum();
return expectedSum-actualSum;
}

Remove all numbers except the first using recursion

Basically what I have to do is to remove all digits and leave the first one. If it's a number under 10 keep that number.
I already made some code but instead of removing all digits following the first, I removed the first digit.
My code:
public static int keepFirstDigit(int num) {
// Can't change anything besides the following code
if(num==0){
return 0;
}
if(num>0){
return num % (int) Math.pow(10, (int) Math.log10(num));
}
return num;
}
If the number is 5, the output should be 5.
If the number is 23 the output should be 2.
If the number is 62363456 the output should be 6.
First, you need to understand what is recursion and how it works.
Recursion means function/method call itself.
in below program removeDigit method calling itself if n is greater than 10 with n = n/10.
try this one.
public class Main {
public static void main(String[] args) {
System.out.println(removeDigit(23219));
}
public static int removeDigit(int n) {
if (Math.abs(n) < 10) {
return n;
}
return removeDigit(n/10);
}
}
for n = 23219
iteration 1
23219 > 10
call removeDigit with n = 23219/10 = 2321
iteration 2
2321 > 10
call removeDigit with n = 2321/10 = 232
iteration 3
232 > 10
call removeDigit with n = 232/10 = 23
iteration 4
23 > 10
call removeDigit with n = 23/10 = 2
iteration 5
2 < 10
So return 2
I am not sure if recursion is the best tool to do it however this should work :
public static int keepFirstDigit(int num) {
//Can't change anything besides the following code
if(num < 10) {
return num;
} else {
return keepFirstDigit(num / 10);
}
}
If num is less then 10 we jest return it. Otherwise we divide num by 10 without the remainder and pass it to recursive method call.
For negative numbers we could change the negative number to positive as this does not affect first digit :
public static int keepFirstDigit(int num) {
num = Math.abs(num);
if(num < 10) {
return num;
} else {
return keepFirstDigit(num / 10);
}
}
We could also do the abs before calling this method and pass it as parameter.
I'm not sure if you need to do it recursiveley but if you don't, I'd do it like this
public static int keepFirstDigit(int num) {
String tempNum = String.valueOf(num).substring(0,1);
return((int) Integer.parseInt(tempNum));
}
but if you do, just use the other examples that have already been posted
This can also be achieved using Strings, maybe think of this:
public static int keepFirstDigit(int num) {
//Can't change anything besides the following code
return Integer.parseInt((num+"").charAt(0)+"");
}
Based on #Pankaj Singh and #michalk answer, here is a working, verifiable solution in Javascript.
It also handle negative and null values.
Run it to see output and results.
(Probably not the fastest, shortest way though)
Result for 0 -> 0
Result for 10 -> 1
Result for -10 -> -1
Result for 9.9999 -> 9
Result for 1.57 -> 1
Result for 23 -> 2
Result for 34.5 -> 3
Result for 5678848 -> 5
Result for -3.14159 -> -3
Result for -28.123 -> -2
// Define a function doing the job
// Take an object as argument, not a number (for updating purpose)
const getFirstDigit = (obj) => {
// Ensure argument is valid
if (!obj || !obj.count) {
return;
}
if ((obj.count >= 0 && obj.count < 10)
/* handle negatives */
|| (obj.count <= 0 && obj.count > -10)) {
// Ensure it is an integer
obj.count = parseInt(obj.count);
} else {
// Divide by ten: update obj.count
obj.count = parseInt(obj.count / 10);
// Recursion: call again since number is greater or equals than 10
getFirstDigit(obj);
}
}
// At the end of recursion stack, obj.count will be an integer < 10 == the first digit of initial number
// Give some inputs (and negative values)
let numbers = [0, 10, -10, 9.9999, 1.57, 23, 34.50, 5678848, -3.14159, -28.123];
for (index in numbers) {
let input = numbers[index];
// Prepare an object to hold our number
let object = { count: input };
// Call the method by passing an object
// Passing an object rather a primitive Number allow the function to update the object by reference
getFirstDigit(object)
// Retrieve object updated (or not) number
let output = object.count;
console.log(`Result for ${input} -> ${output}`);
}

Transform double for Loop to Stream?

I'm just curious if i can switch this
for (String arg : args) {
int number = Integer.parseInt(arg);
int checksum = 0;
for (int digits = 0; digits < 10; digits++) {
checksum += number % 10;
number /= 10;
}
System.out.println(checksum);
}
}
into a piped Java Stream (only that condition, no recursive method etc.).
My first attempt was
public static void main(String... args) {
Stream.of(args)
.?
}
with then somehow use a function like:
class FunctionTest implements Function<String, Integer> {
#Override
public Integer apply(String s) {
int number = Integer.parseInt(s);
int checksum = 0;
IntStream.range(1,10).reduce(number, ()-> ?)
checksum += number % 10;
number /= 10;
return checksum;
}
}
But I guess I come to a dead end with that...
Does someone has a better idea or is it actually impossible?
Arrays.stream(args)
.map(Integer::parseInt)
.map(number -> {
int sum = 0;
for(int i = 0; i < 10; i ++) {
sum += number % 10;
number /= 10;
}
return sum;
})
.forEach(System.out::println);
Or alternatively (note this would not work for negative numbers):
Arrays.stream(args)
.map(number -> number.split(""))
.map(Arrays::stream)
.map(strStream -> strStream.mapToInt(Integer::parseInt))
.map(IntStream::sum)
.forEach(System.out::println);
This one splits the string into its individual character strings, maps them to integers and then sums them
And finally, also a positive number only solution:
Arrays.stream(args)
.map(CharSequence::chars)
.map(chars -> chars.map(Character::getNumericValue))
.map(IntStream::sum)
.forEach(System.out::println);
An approach assuming input are Strings
This is somewhat obscure due to the fact there is only IntStream, but no CharStream. CharSequence.chars() gives an IntStream. '0' maps to 48 according to ASCII, '1' to 49 etc. So you can just subtract 48 to get the int value.
String[]x={"1495","34","333333","-13"};
Arrays.stream(x)
.map(y-> y.chars().map(z->z-48).sum())
.forEach(System.out::println);
As pointed out by JBNizet, that solution does not do exactly the same thing. It does not throw an exception if any of the strings are not Integers (and works for Strings representing integers larger than Integer.MAX_VALUE).
Also, it returns a positive sum for negative numbers (for which the - sign should probably filtered, for example with .filter(Character::isDigit)
Another approach assuming input are Integers
This more like a "translation" of OP's code to IntStream.generate(). The stream starts with the original integer and subsequent elements are generated by division by 10. The, the elements are mapped to modulo by 10.
int[]ints={1495,34,333333,-13};
IntStream.of(ints)
.map( a-> IntStream.iterate(a,b->b/10) // (1)
.map(c->c%10) // (2)
.limit(10) // (3)
.sum())
.forEach(System.out::println);
(1) for example generates for 1495 the following IntStream:
1495 149 14 1 0 0 ...
(2) map to modulo:
5 9 4 1 0 0 ...
(3) since this is an infinite stream, we need a limit
Note that not only arrays and collections are streamable, character sequences are as well. Now, you can stream over the characters and convert each digit to a numerical value before summing, but the conversion only implies subtracting the same offset ('0') from the character and there is already a basic arithmetic solution for summing the same number a number of times, the multiplication:
Arrays.stream(args)
.map(s -> s.chars().sum()-'0'*s.length())
.forEach(System.out::println);
This is concise and efficient.
In case you need support for negative numbers, you can change it to
Arrays.stream(args)
.map(s -> s.startsWith("-")?
'0'*(s.length()-1)-s.chars().skip(1).sum():
s.chars().sum()-'0'*s.length())
.forEach(System.out::println);
The checksum computation is not a good candidate for a stream-based solution, IMO. The loop through the arguments can be transformed to streams, though:
public class Help {
public static void main(String[] args) {
Arrays.stream(args)
.mapToInt(Integer::parseInt)
.map(Help::toCheckSum)
.forEach(System.out::println);
}
private static int toCheckSum(int number) {
int checksum = 0;
for (int digits = 0; digits < 10; digits++) {
checksum += number % 10;
number /= 10;
}
return checksum;
}
}

Java Program Fibonacci Sequence

I am writing a "simple" program to determine the Nth number in the Fibonacci sequence. Ex: the 7th number in the sequence is: 13. I have finished writing the program, it works, but beginning at the 40th number it begins to delay, and takes longer, and longer. My program has to go to the 100th spot in the series.
How can I fix this so it doesn't take so long? This is very basic program, so I don't know all the fancy syntax codes.. my formula is:
if n =1 || n = 0
return n;
else
return F(n-1) + F(n-2);
This works great until it goes past the 40th term. What other statement do I have to add to make it go quicker for higher numbers??
The problem is that because you are using simple recursion, you re-evaluate F(n) multiple times, so your execution time is exponential.
There are two simple ways to fix this:
1) Cache values of F(n) when they are evaluated the first time. Check the cache first before evaluating F(n) to see if you have already calculated it for this n.
2) Use an iterative approach: Calculate F(1), F(2), F(3), etc... until you reach the number you need.
The issue is that your algorithm, while mathematically pure (and nice) isn't very good.
For every number it wants to calculate, it has to calculate two lower ones which in turn have to calculate two lower ones, etc. Your current algorithm has a Big O notation complexity of about O(1.6n), so for very large numbers (100 for example) it takes a long time.
This book, Structure and Interpretation of Computer programs has a nice diagram: showing what happens when you generate fib 5 with your algorithm
(source: mit.edu)
The simplest thing to do is to store F - 1 and F - 2, so that you don't have to calculate them from scratch every time. In other words, rather than using recursion, use a loop. Than means that the complexity of the algorithm goes from O(1.6n) to O(n).
There are a number of solutions. The most straightforward is to use memoization. There's also Binet's formula which will give you the nth fibonacci number in constant time.
For memoization, you store your results for F[a_i] in a map or list of some kind. In the naive recursion, you compute F[4] hundreds of thousands of times, for example. By storing all these results as you find them, the recursion ceases to proceed like a tree and looks like the straightforward iterative solution.
If this isn't homework, use Binet's formula. It's the fastest method available.
Try this example, it calculates the millionth Fibonacci number in a reasonable time frame without any loss of precision.
import java.math.BigInteger;
/*
250000th fib # is: 36356117010939561826426 .... 10243516470957309231046875
Time to compute: 3.5 seconds.
1000000th fib # is: 1953282128707757731632 .... 93411568996526838242546875
Time to compute: 58.1 seconds.
*/
public class Fib {
public static void main(String... args) {
int place = args.length > 0 ? Integer.parseInt(args[0]) : 1000 * 1000;
long start = System.nanoTime();
BigInteger fibNumber = fib(place);
long time = System.nanoTime() - start;
System.out.println(place + "th fib # is: " + fibNumber);
System.out.printf("Time to compute: %5.1f seconds.%n", time / 1.0e9);
}
private static BigInteger fib(int place) {
BigInteger a = new BigInteger("0");
BigInteger b = new BigInteger("1");
while (place-- > 1) {
BigInteger t = b;
b = a.add(b);
a = t;
}
return b;
}
}
Create an array with 100 values, then when you calculate a value for Fib(n), store it in the array and use that array to get the values of Fib(n-1) and Fib(n-2).
If you're calling Fib(100) without storing any of the previously calculated values, you're going to make your java runtime explode.
Pseudocode:
array[0] = 0;
array[1] = 1;
for 2:100
array[n] = array[n-1] + array[n-2];
The problem is not JAVA, but the way you are implementing your Fibonacci algorithm.
You are computing the same values many times, which is slowing your program.
Try something like this : Fibonacci with memoization
F(n)
/ \
F(n-1) F(n-2)
/ \ / \
F(n-2) F(n-3) F(n-3) F(n-4)
/ \
F(n-3) F(n-4)
Notice that many computations are repeated!
Important point to note is this algorithm is exponential because it does not store the result of previous calculated numbers. eg F(n-3) is called 3 times.
Better solution is iterative code written below
function fib2(n) {
if n = 0
return 0
create an array f[0.... n]
f[0] = 0, f[1] = 1
for i = 2...n:
f[i] = f[i - 1] + f[i - 2]
return f[n]
}
For more details refer algorithm by dasgupta chapter 0.2
My solution using Java 8 Stream:
public class Main {
public static void main(String[] args) {
int n = 10;
Fibonacci fibonacci = new Fibonacci();
LongStream.generate(fibonacci::next)
.skip(n)
.findFirst()
.ifPresent(System.out::println);
}
}
public class Fibonacci {
private long next = 1;
private long current = 1;
public long next() {
long result = current;
long previous = current;
current = next;
next = current + previous;
return result;
}
}
If you use the naive approach, you'll end up with an exploding number of same calculations, i.e. to calc fib(n) you have to calc fib(n-1) and fib(n-2). Then to calc fib(n-1) you have to calc fib(n-2) and fib(n-3), etc. A better approach is to do the inverse. You calc starting with fib(0), fib(1), fib(2) and store the values in a table. Then to calc the subsequent values you use the values stored in a table (array). This is also caled memoization. Try this and you should be able to calc large fib numbers.
This is the code in Python, which can easily be converted to C/Java. First one is recursive and second is the iterative solution.
def fibo(n, i=1, s=1, s_1=0):
if n <= i: return s
else: return fibo(n, i+1, s+s_1, s)
def fibo_iter_code(n):
s, s_1 = 1, 0
for i in range(n-1):
temp = s
s, s_1 = s+s_1, temp
print(s)
Too slow...
Better:
(JavaScript example)
function fibonacci(n) {
var a = 0, b = 1;
for (var i = 0; i < n; i++) {
a += b;
b = a - b;
}
return a;
}
import java.util.*;
public class FibonacciNumber
{
public static void main(String[] args)
{
int high = 1, low = 1;
int num;
Scanner in = new Scanner(System.in);
try
{
System.out.print("Enter Number : " );
num = in.nextInt();
System.out.println( low);
while(high < num && num < 2000000000)
{
System.out.println(high);
high = low + high;
low = high - low;
}
} catch (InputMismatchException e) {
System.out.print("Limit Exceeded");
}
}
}
/* Ouput :
Enter Number : 1999999999
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
-1323752223
512559680
-811192543
-298632863
-1109825406
-1408458269
1776683621
368225352 */
Naive implementation is natural and elegant but during execution recursive calls are creating binary tree. Beside already mentioned memoization, cashing of previous F(n) results and avoiding of unnecessary tree traversal, you can go for tail call optimization, already mentioned iterative or matrix multiplication. For example, Java 8 memoization:
private static final Map<Long, Long> memo = new HashMap<>();
static {
memo.put(0L, 0L);
memo.put(1L, 1L);
}
public static void main(String[] args) {
System.out.println(fibonacci(0));
System.out.println(fibonacci(43));
System.out.println(fibonacci(92));
}
public static long fibonacci(long n) {
return memo.computeIfAbsent(n, m -> fibonacci(m - 1) + fibonacci(m - 2));
}
Or maybe tail call optimized version:
interface FewArgs<T, U, V, R> {
public R apply(T t, U u, V v);
}
static FewArgs<Long, Long, Long, Long> tailRecursive;
static {
tailRecursive = (a, b, n) -> {
if (n > 0)
return tailRecursive.apply(b, a + b, n - 1);
return a;
};
}
You call it with a = 0, b = 1, n is required nth Fibonacci number but must be smaller than 93.
More efficient ways to calculate Fibonacci numbers are matrix squaring, you will find example on my blog, and Binet formula
You can use the caching technic. Since f(n)= f(n-1)+f(n-2) , you'll calculate f(n-2) one more time when you calculate f(n-1). So simply treat them as two incremental numbers like below:
public int fib(int ithNumber) {
int prev = 0;
int current = 1;
int newValue;
for (int i=1; i<ithNumber; i++) {
newValue = current + prev;
prev = current;
current = newValue;
}
return current;
}
It looks better with multiple statements of ternary operator.
static int fib(int n) {
return n > 5 ? fib(n-2) + fib(n-1)
: n < 2 || n == 5 ? n
: n - 1;
}

Categories

Resources