'Checking if the Given numger is an Armstrong number with Java 8 Streams
I'm having an issue while checking if the supplied number is Armstrong or not.
I'm passing the int value of 370, but as a result I'm getting the value of 343.
Can someone point out what I'm missing?
Input: 370
Expected: 370
static int isArmStrong(int num) {
return IntStream.rangeClosed(1, num)
.map(i -> i / 10)
.map(i -> i % 10)
.reduce(1, (a, b)-> (b * b * b));
}
Solution 1:[1]
To generate the List of Armstrong number with java 8 stream.
static boolean isArmStrong(int num) {
return num==armStrongViaStream(num);
}
//via Stream
static int armStrongViaStream(int num) {
int size = String.valueOf(num).length();
return IntStream.iterate(num, i->i/10)
.limit(size)
.map(i-> (int)Math.pow(i%10, size))
.sum();
}
//List via Stream
static List<Integer> armStrongListUpto(int num){
List<Integer> list=new ArrayList<>();
list=IntStream.rangeClosed(0, num)
.filter(i->isArmStrong(i)).boxed()
.collect(Collectors.toList());
return list;
}
Main Method
System.out.println("List via Java Stream ->"+armStrongListUpto(500));
Output will return a list.
List via Java Stream ->[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407]
Solution 2:[2]
You have to iterate over the digits of the given number. But instead you've created a stream of numbers from 1 to the given number inclusive.
And you've hard-coded the power of 3 is (i.e. your solution is intended to deal only with 3-digit numbers).
Also, there's a bug in the reduce operation:
reduce(1,(a,b)-> (b*b*b))
What your method is actually returns is a cube of the last element in the stream, which for the input 370 happens to be a 7. Because you are ignoring the argument a in the accumulator (a - represents a sum accumulated so far and b - is a next element).
And it'll be better if isArmstrong method would return a boolean value. Because it's meant to perform a check as you've and by convention methods that start with is or has are expected to return a boolean.
To address this problem correctly, you need to follow the classical algorithm (wiki) iterating over the digits of the given number.
You can do it with streams by the iterate() operation. Its Java 8 flavor which take two arguments (a seed and a unary operator that is used to generate the next element) creates an infinite stream. You need to apply the limit() operation to trim the number of elements in the stream to the number of digits in the given number.
Apply map() to obtain the power of every element and then apply the terminal operation sum() to get the result.
public static boolean isArmstrong(int num) {
return num == getArmstrongSum(num);
}
public static int getArmstrongSum(int num) {
int pow = String.valueOf(num).length();
return IntStream.iterate(num, i -> i / 10)
.limit(pow)
.map(i -> (int) Math.pow(i % 10, pow))
.sum();
}
main()
public static void main(String[] args) {
System.out.println(getArmstrongSum(370));
System.out.println(isArmstrong(370));
}
Output
370
true
Solution 3:[3]
if we need to generate list of Armstrong number between a range in Java 8 Streams.
static List<Integer> armStrongBetweenNum(int start,int end){
List<Integer> list=new ArrayList<>();
list=IntStream.rangeClosed(start, end)
.filter(i->isArmStrong(i)).boxed()
.collect(Collectors.toList());
return list;
}
Main function(call)
System.out.println("Armstrong num between given end points ->"+armStrongBetweenNum(1, 500));
output
Armstrong num between given end points ->[1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Maveric |
| Solution 2 | |
| Solution 3 | Maveric |
