什么时候应该在 Java 中使用 IntStream.range?
我想知道什么时候可以有效地使用 IntStream.range
.我不确定 IntStream.range
有多大用处的三个原因.
I would like to know when I can use IntStream.range
effectively. I have three reasons why I am not sure how useful IntStream.range
is.
(请将开始和结束视为整数.)
(Please think of start and end as integers.)
如果我想要一个数组,
[start, start+1, ..., end-2, end-1]
,下面的代码要快得多.
If I want an array,
[start, start+1, ..., end-2, end-1]
, the code below is much faster.
int[] arr = new int[end - start];
int index = 0;
for(int i = start; i < end; i++)
arr[index++] = i;
这可能是因为 IntStream.range(start, end).toArray()
中的 toArray()
很慢.
This is probably because toArray()
in IntStream.range(start, end).toArray()
is very slow.
我使用 MersenneTwister 来洗牌.(我在线下载了 MersenneTwister 课程.)我认为没有办法使用 MersenneTwister 随机播放 IntStream
.
I use MersenneTwister to shuffle arrays. (I downloaded MersenneTwister class online.) I do not think there is a way to shuffle IntStream
using MersenneTwister.
我不认为仅仅从 start
到 end-1
获取 int
数字是有用的.我可以使用for(int i = start; i < end; i++)
,看起来更简单,也不慢.
I do not think just getting int
numbers from start
to end-1
is useful. I can use for(int i = start; i < end; i++)
, which seems easier and not slow.
你能告诉我什么时候应该选择 IntStream.range
?
Could you tell me when I should choose IntStream.range
?
推荐答案
IntStream.range
有多种用途.
一种是使用 int
值本身:
One is to use the int
values themselves:
IntStream.range(start, end).filter(i -> isPrime(i))....
另一种是做某事N次:
IntStream.range(0, N).forEach(this::doSomething);
您的情况(1)是创建一个填充范围的数组:
Your case (1) is to create an array filled with a range:
int[] arr = IntStream.range(start, end).toArray();
您说这非常慢",但与其他受访者一样,我怀疑您的基准测试方法.对于小型阵列,流设置确实有更多开销,但这应该小到不明显.对于大型数组,开销应该可以忽略不计,因为填充大型数组主要取决于内存带宽.
You say this is "very slow" but, like other respondents, I suspect your benchmark methodology. For small arrays there is indeed more overhead with stream setup, but this should be so small as to be unnoticeable. For large arrays the overhead should be negligible, as filling a large array is dominated by memory bandwidth.
有时您需要填充现有数组.你可以这样做:
Sometimes you need to fill an existing array. You can do that this way:
int[] arr = new int[end - start];
IntStream.range(0, end - start).forEach(i -> arr[i] = i + start);
有一个实用方法 Arrays.setAll
可以更简洁地做到这一点:
There's a utility method Arrays.setAll
that can do this even more concisely:
int[] arr = new int[end - start];
Arrays.setAll(arr, i -> i + start);
还有 Arrays.parallelSetAll
可以并行填充现有数组.在内部,它只是使用 IntStream
并在其上调用 parallel()
.这应该为多核系统上的大型阵列提供加速.
There is also Arrays.parallelSetAll
which can fill an existing array in parallel. Internally, it simply uses an IntStream
and calls parallel()
on it. This should provide a speedup for large array on a multicore system.
我发现我在 Stack Overflow 上的很多答案都涉及到使用 IntStream.range
.您可以使用搜索框中的这些搜索条件来搜索它们:
I've found that a fair number of my answers on Stack Overflow involve using IntStream.range
. You can search for them using these search criteria in the search box:
user:1441122 IntStream.range
IntStream.range
的一个应用我发现特别有用的是对数组的元素进行操作,其中数组索引以及数组的值都参与了计算.有一大堆这样的问题.
One application of IntStream.range
I find particularly useful is to operate on elements of an array, where the array indexes as well as the array's values participate in the computation. There's a whole class of problems like this.
例如,假设您想在一个数组中找到不断增加的数字运行的位置.结果是第一个数组的索引数组,其中每个索引都指向运行的开始.
For example, suppose you want to find the locations of increasing runs of numbers within an array. The result is an array of indexes into the first array, where each index points to the start of a run.
要计算此值,请观察运行从值小于前一个值的位置开始.(运行也从位置 0 开始).因此:
To compute this, observe that a run starts at a location where the value is less than the previous value. (A run also starts at location 0). Thus:
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 循环,您必须处理复制和调整大小,这会分散循环的核心逻辑.
Of course, you could do this with a for-loop, but I find that using IntStream
is preferable in many cases. For example, it's easy to store an unknown number of results into an array using toArray()
, whereas with a for-loop you have to handle copying and resizing, which distracts from the core logic of the loop.
最后,并行运行 IntStream.range
计算要容易得多.
Finally, it's much easier to run IntStream.range
computations in parallel.
相关文章