I'm trying to learn Streams API.
I want to find a target
sum in an array by adding integers until it's reached, then return the indexes which add up to the target by using streams.
For example, if the provided array was {1, 2, 3, 4}
and the target
was 4
, the method would return an int array of the indexes {0,2}
.
The code I have now will not printout anything from the IntStream
public static int[] twoSum(int[] numbers, int target)
{
IntStream.of(0, numbers.length - 1).boxed()
.flatMap(i -> IntStream.range(i , numbers.length - 1).boxed()
.filter(j -> numbers[j] numbers[i] == target)
.flatMap(j -> Stream.of(new int[]{i , j}, new int[] {j,i})))
.forEach(nu -> System.out.println(Arrays.toString(num)));
return numbers;
}
public static void main(String[] args){
System.out.println(Arrays.toString(Dups.twoSum(new int[]{1,2,5,1}, 4)));
}
CodePudding user response:
Not sure, but if you are using this code exactly, May it is because of the typo you have after foreach. You are initiating the input as nu
, but printing it as num
.
.forEach(num -> System.out.println(Arrays.toString(num)));
Perhaps replacing this with what you have will solve the problem.
CodePudding user response:
Instead of using a for loop you can nest two IntStreams
to produce the desired result (as I understand it). This will return all pairs that sum to the target value. This does not include elements of the array that added to themselves equal the target. So for a target of 4
, [2, 2]
is not included as a result
int[] arr1 = { 1, 2, 3, 4, 5, -2, -1, -3, -4, -5 };
int[][] array = twoSum(arr1, 4);
for (int[] a : array) {
System.out.println(Arrays.toString(a));
}
prints
[1, 3]
[5, -1]
- First, stream a range of ints from 0 to one less than the array size.
- then use
boxed
to convert the int to an object. - Then you
flatMap
(combine the nested streams into one) anotherIntStream
starting with one more than the previous stream, but the full length of the array. - still within the
flatMap
construct, and using the values of theIntStreams
as the indices to the supplied array, filter away values that don't sum to the target, and create an array of the two numbers that did add up (this could also be replaced with the indices of the array if desired). - Then return this array of arrays as a result.
public static int[][] twoSum(int[] numbers, int target) {
return IntStream.range(0, numbers.length - 1)
.boxed()
.flatMap(i -> IntStream.range(i 1, numbers.length)
.filter(k -> numbers[i] numbers[k] == target)
.mapToObj(k -> new int[] { numbers[i],numbers[k] }))
.toArray(int[][]::new);
}
CodePudding user response:
You can generate a Map
that will associate a value that required to be added to a particular element in order to obtain a target
sum (a key) and the index of an array element (a value).
Then create a stream over the indices of the given array, filter out the first element that matches a key in the map and construct a two-value array based on it.
If a result was not found - return an empty array.
The algorithm runs in a linear time. Only two iterations over the sourc array are required.
public static int[] twoSum(int[] numbers, int target) {
Map<Integer, Integer> sumMap = getSumMap(numbers, target);
return IntStream.range(0, numbers.length)
.filter(i -> sumMap.containsKey(numbers[i]))
.mapToObj(i -> new int[]{i, sumMap.get(numbers[i])})
.findFirst()
.orElse(new int[0]);
}
public static Map<Integer, Integer> getSumMap(int[] numbers, int target) {
rreturn IntStream.range(0, numbers.length)
.boxed()
.collect(Collectors.toMap(
i -> target - numbers[i], // a key - dif between target sum and a current element
Function.identity(), // a value - index of the current element
(left, right) -> left)); // resolving duplicates
}
main()
- demo
public static void main(String[] args) {
System.out.println(Arrays.toString(twoSum(new int[]{1, 4, 3, 0, 4, 1}, 4)));
}
Output
[0, 2] // indices of the first pair of elements (1, 3) that can produce the sum of `4`