I am new to Java 8.
I tried several ways to use the Streams API to solve the problem where we have been given an array of int
, let say
{48, 44, 4, 88, 84, 16, 12, 13}
All I need to do is to find the occurrence of the given digit, let's say 4
, in the array.
I tried the following code.
int[] array = new int[] {48,44,4,88,84,16,12,13};
List<Integer> list = new ArrayList<Integer>();
for(int i:array) {
list.add(i);
}
List<Integer> l = list.stream().filter(n -> n % 10)
.map(n -> n % 10)
.collect(Collectors.toList());
System.out.println(l);
Please advise me the way to solve it with Streams API.
CodePudding user response:
I think an easy way to do this is to convert the list of numbers to a string and count the ocurrences of the selected digit.
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15);
for(int i = 0; i < 10; i ) {
System.out.println("Digit: " i " -> Ocurrences: " countDigit(i, numbers);
}
}
public static long countDigit(int target, List<Integer> numbers) {
return numbers.stream().map(Object::toString) // Convert each number to string
.collect(Collectors.joining()) // Join all of them into single string
.chars() // Give me a stream of its characters
.filter(c -> c == Character.forDigit(targer, 10)) // I just want the ones that are the same as my target
.count(); // How many of them are there?
}
CodePudding user response:
Here is one way.
- stream the array
- then in map, count the number of fours in each value using the remainder(%) operator.
- then return the count
- and sum those counts
int[] array = new int[] { 48, 44, 4, 88, 84, 16, 12, 13 };
int count = Arrays.stream(array).map(k-> {
int sum = 0;
while (k > 3) {
sum = (k % 10 == 4) ? 1 : 0;
k/=10;
}
return sum;
}).sum();
System.out.printf("There are %d fours.%n"m count);
prints
There are 5 fours.
If you're using Java 16 , you can use mapMulti
- simply put a 1 on the stream for every occurrence of 4.
- them sum them.
int count = Arrays.stream(array).mapMulti((i,consumer)->{
while (i > 3) {
if ((i) == 4) {
consumer.accept(1);
}
i/=10;
}}).sum();
And just for fun a third and less efficient way.
- convert the value to a String
- "remove" all characters except 4.
- return the length of remaining String.
- sum the lengths.
int count = Arrays.stream(array)
.map(i -> Integer.valueOf(i).toString()
.replaceAll("[^4]", "").length())
.sum();
CodePudding user response:
First, you need to obtain a stream from the given array of int[]
. You can do it either by using the static method IntStream.of
, or with Arrays
utility class and it's method stream()
.
Both will give you an IntStream
- a stream of int
primitives. In order to collect stream elements into a list you need to convert it to a stream of objects. For that you can apply method boxed()
on the stream pipeline and each int
element will get wrapped with Integer
object.
In order to find all elements in the given list that contain a target digit (4
), you can to turn the target digit into a string and then apply a filter
based on it.
public static List<Integer> findOccurrencesOfDigit(List<Integer> source,
int digit) {
String target = String.valueOf(digit);
return source.stream()
.filter(n -> String.valueOf(n).contains(target))
.collect(Collectors.toList());
}
main()
public static void main(String[] args) {
int[] nums = {48,44,4,88,84,16,12,13};
System.out.println(findOccurrencesOfDigit(nums, 4));
}
Output
[48, 44, 4, 84]
Note: method filter()
expects a Predicate
(a function represented by a boolean condition, that takes an element and return true
of false
)
Your attempt to create a predicate filter(n -> n % 10)
is incorrect syntactically and logically. n % 10
doesn't produce a boolean value, it'll give the right most digit of n
.
If you want to use modulus (%
) operator to create a predicate, correct condition you have to divide the element by 10
until it'll not become equal to 0
, and check before every division weather remained it's equal to the target digit. It could be done like that:
public static List<Integer> findOccurrencesOfDigit(int[] source,
int digit) {
String target = String.valueOf(digit);
return IntStream.of(source)
.filter(n -> containsDigit(n, digit))
.boxed()
.collect(Collectors.toList());
}
You can utilize this method inside a lambda like that (note:it's preferred way to avoid multiline lambda expressions by extracting them into separate methods)
filter(n -> containsDigit(n, digit))