使用IntStream.range
有几种方法。
其中之一是使用int
值本身:
IntStream.range(start, end).filter(i -> isPrime(i))....
另一种方法是重复N次某件事:
IntStream.range(0, N).forEach(this::doSomething);
你的情况(1)是要创建一个填充有一定范围的数组:
int[] arr = IntStream.range(start, end).toArray();
你说这个过程非常缓慢,但是和其他回答者一样,我怀疑你的基准测试方法。对于小数组来说,确实有更多的流设置开销,但这应该非常小到无法察觉。对于大数组来说,开销应该可以忽略,因为填充一个大数组受内存带宽的影响。
有时你需要填充一个已存在的数组,你可以这样做:
int[] arr = new int[end - start];
IntStream.range(0, end - start).forEach(i -> arr[i] = i + start);
有一个实用方法 Arrays.setAll
,可以更加简洁地完成这个任务:
int[] arr = new int[end - start];
Arrays.setAll(arr, i -> i + start);
还有一个 Arrays.parallelSetAll
方法可以并行地填充一个已存在的数组。内部实现是使用了 IntStream
并在其上调用了 parallel()
方法。这样可以在多核系统上为大型数组提供加速。
我发现我的很多 Stack Overflow 回答都涉及到使用 IntStream.range
方法。你可以在搜索框中使用以下搜索条件进行查找:
user:1441122 IntStream.range
我发现IntStream.range
的一个特别有用的应用是在数组元素上进行操作,其中数组索引以及数组的值都参与计算。有一整类这样的问题。
例如,假设你想要找到数组中递增数字的位置。结果是一个指向第一个数组中每个递增序列开头的索引数组。
为了计算这个问题,观察到一个递增序列从前一个数值小于当前数值的位置开始。(一个递增序列也可以从位置0开始)。因此:
int[] arr = { 1, 3, 5, 7, 9, 2, 4, 6, 3, 5, 0 };
int[] runs = IntStream.range(0, arr.length)
.filter(i -> i == 0 || arr[i-1] > arr[i])
.toArray();
System.out.println(Arrays.toString(runs));
[0, 5, 8, 10]
当然,你可以用for循环做到这一点,但是我发现在许多情况下使用IntStream
更可取。例如,使用toArray()
轻松地将未知数量的结果存储到数组中,而使用for循环则必须处理复制和调整大小,这会分散循环的核心逻辑。
最后,使用IntStream.range
计算更容易并行运行。
IntStream.range()
生成一个流,并将其作为参数传递给另一个方法。而用for
语句做不到这一点。 - bizicloprange2
方法什么也没做。当然,将值写入数组需要比什么都不做更多的时间,但这与你声称toArray
比执行相同操作的for
循环慢有何关系? - Holger