Java 8 流,如何在不抛出运行时异常的情况下 "break" 在 reduce 或 collect 中?
Java 8 stream, how to "break" in reduce or in collect without throwing runtime exception?
这个问题是在 forEach
的背景下提出的。
评论(答案被接受后):我接受了@nullpointer的答案,但它只在我的代码示例的上下文中是正确的,而不是关于break-的一般问题减少能力..
问题:
但是有没有办法在 reduce
或 collect
中过早地到 "break",而无需遍历所有流元素? (这意味着我需要在迭代时累积状态,所以我使用 reduce
或 collect
)。
简而言之:我需要迭代流中的所有元素(元素是整数并从小到大排序),但是查看 2 个相邻元素并比较它们,如果它们之间的差异大于 1,我需要 "break" 并停止 "accumulate the state" 我需要 return 最后传递的元素。
抛出 RuntimeException
的变体和传递外部状态的变体 - 对我不利。
带注释的代码示例:
public class Solution {
public int solution(int[] A) {
Supplier<int[]> supplier = new Supplier<int[]>() {
@Override
public int[] get() {
//the array describes the accumulated state:
//first element in the array , if set > 0, means - the result is achieved, we can stop iterate over the rest elements
//second element in the array will represent the "previous element" while iterating the stream
return new int[]{0, 0};
}
};
//the array in accumulator describes the accumulated state:
//first element in the array , if set > 0, means - the result is achieved, we can stop iterate over the rest elements
//second element in the array will represent the "previous element" while iterating the stream
ObjIntConsumer<int[]> accumulator = new ObjIntConsumer<int[]>() {
@Override
public void accept(int[] sett, int value) {
if (sett[0] > 0) {
;//do nothing, result is set
} else {
if (sett[1] > 0) {//previous element exists
if (sett[1] + 1 < value) {
sett[0] = sett[1] + 1;
} else {
sett[1] = value;
}
} else {
sett[1] = value;
}
}
}
};
BiConsumer<int[], int[]> combiner = new BiConsumer<int[], int[]>() {
@Override
public void accept(int[] sett1, int[] sett2) {
System.out.println("Combiner is not used, we are in sequence");
}
};
int result[] = Arrays.stream(A).sorted().filter(value -> value > 0).collect(supplier, accumulator, combiner);
return result[0];
}
/**
* We have an input array
* We need order it, filter out all elements that <=0 (to have only positive)
* We need find a first minimal integer that does not exist in the array
* In this example it is 5
* Because 4,6,16,32,67 positive integers array is having 5 like a minimum that not in the array (between 4 and 6)
*
* @param args
*/
public static void main(String[] args) {
int[] a = new int[]{-2, 4, 6, 16, -7, 0, 0, 0, 32, 67};
Solution s = new Solution();
System.out.println("The value is " + s.solution(a));
}
}
流 API 到 break
中没有任何方法。您可以抛出异常,但这确实不是一个好主意。
但你是对的 - 你可以使用 reduce 找到集合
中的最后一个 "successed" 元素
整数列表:
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,12,13);
让我们找到第 i 个元素的值,其中 element[i+1]-element[i] > 1
:
int result = integers.stream().reduce((i1,i2) -> (i2-i1) > 1 ? i1 : i2).get();
对于这种情况,结果将等于 10。
然后你就可以得到你的公共列表的子列表;
integers.subList(0,integers.indexOf(result)+1).forEach(s-> System.out.println(s));
对于有效集合的情况(当没有元素的差异大于 1 时),result
将等于最后一个元素的值,子列表将等于列表。所以你可以添加一些检查来避免 .subList
在不需要的时候。
减少示例:
{1,2,3,5}
第一步:
i1 = 1; i2 = 2; -> reduce(), difference =1, so we reduce this pair to i2 (2) -> new collection is{2,3,5}
第二步
i1 = 2; i2 = 3; -> reduce(), difference =1, so we reduce this pair to i2 (3) -> new collection is{3,5}
第三步
i1 = 3; i2 = 5; -> reduce(), difference >1, so we reduce this pair to i1 (3) -> new collection is {3} and it transforms to Optional<Integer>
给定一个数组作为输入,在我看来你正在寻找这样的东西:
int stateStream(int[] arr) {
return IntStream.range(0, arr.length - 1)
.filter(i -> arr[i + 1] - arr[i] > 1) // your condition
.mapToObj(i -> arr[i])
.findFirst() // first such occurrence
.map(i -> i + 1) // to add 1 to the point where the cehck actually failed
.orElse(0); // some default value
}
或从头开始,同时将其转换为排序和过滤的值列表:
int stateStream(int[] arr) {
List<Integer> list = Arrays.stream(arr)
.boxed().sorted()
.filter(value -> value > 0)
.collect(Collectors.toList());
return IntStream.range(0, list.size() - 1)
.filter(i -> list.get(i + 1) - list.get(i) > 1)
.mapToObj(list::get)
.findFirst()
.map(i -> i + 1)
.orElse(0);
}
这个问题是在 forEach
的背景下提出的。
评论(答案被接受后):我接受了@nullpointer的答案,但它只在我的代码示例的上下文中是正确的,而不是关于break-的一般问题减少能力..
问题:
但是有没有办法在 reduce
或 collect
中过早地到 "break",而无需遍历所有流元素? (这意味着我需要在迭代时累积状态,所以我使用 reduce
或 collect
)。
简而言之:我需要迭代流中的所有元素(元素是整数并从小到大排序),但是查看 2 个相邻元素并比较它们,如果它们之间的差异大于 1,我需要 "break" 并停止 "accumulate the state" 我需要 return 最后传递的元素。
抛出 RuntimeException
的变体和传递外部状态的变体 - 对我不利。
带注释的代码示例:
public class Solution {
public int solution(int[] A) {
Supplier<int[]> supplier = new Supplier<int[]>() {
@Override
public int[] get() {
//the array describes the accumulated state:
//first element in the array , if set > 0, means - the result is achieved, we can stop iterate over the rest elements
//second element in the array will represent the "previous element" while iterating the stream
return new int[]{0, 0};
}
};
//the array in accumulator describes the accumulated state:
//first element in the array , if set > 0, means - the result is achieved, we can stop iterate over the rest elements
//second element in the array will represent the "previous element" while iterating the stream
ObjIntConsumer<int[]> accumulator = new ObjIntConsumer<int[]>() {
@Override
public void accept(int[] sett, int value) {
if (sett[0] > 0) {
;//do nothing, result is set
} else {
if (sett[1] > 0) {//previous element exists
if (sett[1] + 1 < value) {
sett[0] = sett[1] + 1;
} else {
sett[1] = value;
}
} else {
sett[1] = value;
}
}
}
};
BiConsumer<int[], int[]> combiner = new BiConsumer<int[], int[]>() {
@Override
public void accept(int[] sett1, int[] sett2) {
System.out.println("Combiner is not used, we are in sequence");
}
};
int result[] = Arrays.stream(A).sorted().filter(value -> value > 0).collect(supplier, accumulator, combiner);
return result[0];
}
/**
* We have an input array
* We need order it, filter out all elements that <=0 (to have only positive)
* We need find a first minimal integer that does not exist in the array
* In this example it is 5
* Because 4,6,16,32,67 positive integers array is having 5 like a minimum that not in the array (between 4 and 6)
*
* @param args
*/
public static void main(String[] args) {
int[] a = new int[]{-2, 4, 6, 16, -7, 0, 0, 0, 32, 67};
Solution s = new Solution();
System.out.println("The value is " + s.solution(a));
}
}
流 API 到 break
中没有任何方法。您可以抛出异常,但这确实不是一个好主意。
但你是对的 - 你可以使用 reduce 找到集合
整数列表:
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,12,13);
让我们找到第 i 个元素的值,其中 element[i+1]-element[i] > 1
:
int result = integers.stream().reduce((i1,i2) -> (i2-i1) > 1 ? i1 : i2).get();
对于这种情况,结果将等于 10。 然后你就可以得到你的公共列表的子列表;
integers.subList(0,integers.indexOf(result)+1).forEach(s-> System.out.println(s));
对于有效集合的情况(当没有元素的差异大于 1 时),result
将等于最后一个元素的值,子列表将等于列表。所以你可以添加一些检查来避免 .subList
在不需要的时候。
减少示例:
{1,2,3,5}
第一步:
i1 = 1; i2 = 2; -> reduce(), difference =1, so we reduce this pair to i2 (2) -> new collection is{2,3,5}
第二步
i1 = 2; i2 = 3; -> reduce(), difference =1, so we reduce this pair to i2 (3) -> new collection is{3,5}
第三步
i1 = 3; i2 = 5; -> reduce(), difference >1, so we reduce this pair to i1 (3) -> new collection is {3} and it transforms to Optional<Integer>
给定一个数组作为输入,在我看来你正在寻找这样的东西:
int stateStream(int[] arr) {
return IntStream.range(0, arr.length - 1)
.filter(i -> arr[i + 1] - arr[i] > 1) // your condition
.mapToObj(i -> arr[i])
.findFirst() // first such occurrence
.map(i -> i + 1) // to add 1 to the point where the cehck actually failed
.orElse(0); // some default value
}
或从头开始,同时将其转换为排序和过滤的值列表:
int stateStream(int[] arr) {
List<Integer> list = Arrays.stream(arr)
.boxed().sorted()
.filter(value -> value > 0)
.collect(Collectors.toList());
return IntStream.range(0, list.size() - 1)
.filter(i -> list.get(i + 1) - list.get(i) > 1)
.mapToObj(list::get)
.findFirst()
.map(i -> i + 1)
.orElse(0);
}