我什么时候应该在 Java 中使用 IntStream.range?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38998514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When should I use IntStream.range in Java?
提问by Nickel
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.
我想知道我什么时候可以IntStream.range
有效使用。我有三个原因为什么我不确定它有多大用处IntStream.range
。
(Please think of start and end as integers.)
(请将开始和结束视为整数。)
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;
This is probably because
toArray()
inIntStream.range(start, end).toArray()
is very slow.I use MersenneTwister to shuffle arrays. (I downloaded MersenneTwister class online.) I do not think there is a way to shuffle
IntStream
using MersenneTwister.I do not think just getting
int
numbers fromstart
toend-1
is useful. I can usefor(int i = start; i < end; i++)
, which seems easier and not slow.
如果我想要一个数组,
[start, start+1, ..., end-2, end-1]
下面的代码要快得多。int[] arr = new int[end - start]; int index = 0; for(int i = start; i < end; i++) arr[index++] = i;
这可能是因为
toArray()
inIntStream.range(start, end).toArray()
非常慢。我使用 MersenneTwister 来洗牌数组。(我在线下载了 MersenneTwister 课程。)我认为没有办法
IntStream
使用 MersenneTwister进行随机播放。我不认为仅仅
int
从start
to获取数字end-1
是有用的。我可以使用for(int i = start; i < end; i++)
,这看起来更容易而且不慢。
Could you tell me when I should choose IntStream.range
?
你能告诉我什么时候该选择IntStream.range
吗?
回答by RobAu
Basically, if you want Stream
operations, you can use the range()
method. For example, to use concurrency or want to use map()
or reduce()
. Then you are better off with IntStream
.
基本上,如果你想要Stream
操作,你可以使用该range()
方法。例如,要使用并发或要使用map()
或reduce()
。那么你最好使用IntStream
.
For example:
例如:
IntStream.range(1, 5).parallel().forEach(i -> heavyOperation());
Or:
或者:
IntStream.range(1, 5).reduce(1, (x, y) -> x * y)
// > 24
You can achieve the second example also with a for-loop, but you need intermediate variables etc.
您也可以使用 for 循环来实现第二个示例,但是您需要中间变量等。
Also, if you want the first match for example, you can use findFirst()
and cousins to stop consuming the rest of the Stream
另外,如果你想要第一场比赛,你可以使用findFirst()
和堂兄弟来停止消耗剩下的比赛Stream
回答by tonakai
IntStream.range returns a range of integers as a stream so you can do stream processing over it.
IntStream.range 将一系列整数作为流返回,以便您可以对其进行流处理。
like taking square of each element
就像对每个元素取平方
IntStream.range(1, 10).map(i -> i * i);
回答by CoderCroc
It totally depends on the use case. However, the syntax and stream API adds lot of easy one liners which can definitely replace the conventional loops.
这完全取决于用例。然而,语法和流 API 增加了许多简单的单行代码,绝对可以取代传统的循环。
IntStream
is really helpful and syntactic sugarin some cases,
IntStream
在某些情况下真的很有帮助和语法糖,
IntStream.range(1, 101).sum();
IntStream.range(1, 101).average();
IntStream.range(1, 101).filter(i -> i % 2 == 0).count();
//... and so on
Whatever you can do with IntStream
you can do with conventional loops. As one liner is more precise to understand and maintain.
无论你能做什么,IntStream
你都可以用传统的循环来做。作为一个班轮是更精确的理解和维护。
Still for negative loops we can not use IntStream#range
, it only works in positive increment. So following is not possible,
仍然对于我们不能使用的负循环IntStream#range
,它仅适用于正增量。所以以下是不可能的,
for(int i = 100; i > 1; i--) {
// Negative loop
}
Case 1 :Yes conventional loop is much faster in this case as
toArray
has a bit overhead.Case 2 :I don't know anything about it, my apologies.
Case 3 :
IntStream
is not slow at all,IntStream.range
and conventional loop are almost samein terms of performance.
情况 1:是的,在这种情况下,传统循环要快得多,因为
toArray
有一点开销。案例 2:我对此一无所知,抱歉。
案例3:
IntStream
一点也不慢,IntStream.range
常规循环在性能上几乎相同。
See :
看 :
回答by biziclop
Here's an example:
下面是一个例子:
public class Test {
public static void main(String[] args) {
System.out.println(sum(LongStream.of(40,2))); // call A
System.out.println(sum(LongStream.range(1,100_000_000))); //call B
}
public static long sum(LongStream in) {
return in.sum();
}
}
So, let's look at what sum()
does: it counts the sum of an arbitrary stream of numbers. We call it in two different ways: once with an explicit list of numbers, and once with a range.
那么,让我们看看sum()
它是做什么的:它计算任意数字流的总和。我们以两种不同的方式调用它:一种是明确的数字列表,另一种是范围。
If you only had call A
, you might be tempted to put the two numbers into an array and pass it to sum()
but that's clearly not an option with call B
(you'd run out of memory). Likewise you could just pass the start and end for call B
, but then you couldn't support the case of call A
.
如果您只有call A
,您可能很想将这两个数字放入一个数组中并将其传递给,sum()
但这显然不是一个选项call B
(您会耗尽内存)。同样,您可以只传递 的开始和结束call B
,但是您无法支持call A
.
So to sum it up, ranges are useful here because:
总而言之,范围在这里很有用,因为:
- We need to pass them around between methods
- The target method doesn't just work on ranges but any stream of numbers
- But it only operates on individual numbers of the stream, reading them sequentially. (This is why shuffling with streams is a terrible idea in general.)
- 我们需要在方法之间传递它们
- 目标方法不仅适用于范围,还适用于任何数字流
- 但它只对流的单个数字进行操作,按顺序读取它们。(这就是为什么用流改组通常是一个糟糕的主意。)
There is also the readability argument: code using streams can be much more concise than loops, and thus more readable, but I wanted to show an example where a solution relying on IntStrean
s is functionally superior too.
还有一个可读性论点:使用流的代码比循环更简洁,因此更具可读性,但我想展示一个示例,其中依赖IntStrean
s的解决方案在功能上也更优越。
I used LongStream
to emphasise the point, but the same goes for IntStream
我曾经LongStream
强调过这一点,但同样适用于IntStream
And yes, for simple summing this may look like a bit of an overkill, but consider for example reservtheitroad sampling
是的,对于简单的总结,这可能看起来有点矫枉过正,但请考虑例如水库采样
回答by OldCurmudgeon
You could implement your Mersenne Twister as an Iterator
and stream from that.
您可以将您的 Mersenne Twister 实现为 anIterator
并从中进行流式传输。
回答by Jean-Fran?ois Savard
Here are few differences that comes to my head between IntStream.range
and traditional forloops :
以下是我想到的IntStream.range
与传统for循环之间的一些差异:
IntStream
are lazily evaluated, the pipeline is traversed when calling a terminaloperation. For loops evaluate at each iteration.IntStream
will provides you some functions that are commonly applied to a range of ints such assum
andavg
.IntStream
will allow you to code multiple operation over a range of int in a functional way which read more fluently - specially if you have a lot of operations.
IntStream
被惰性求值,调用终端操作时会遍历管道。For 循环在每次迭代时进行评估。IntStream
将为您提供一些通常应用于一系列整数的函数,例如sum
和avg
。IntStream
将允许您以更流畅的功能方式对一系列 int 进行多个操作编码 - 特别是如果您有很多操作。
So basically use IntStream
when one or more of these differences are useful to you.
所以基本上IntStream
在这些差异中的一个或多个对您有用时使用。
But please bear in mind that shuffling a Stream
sound quite strange as a Stream
is not a data structure and therefore it does not really make sense to shuffle it (in case you were planning on building a special IntSupplier
). Shuffle the result instead.
但是请记住,将 a 的Stream
声音混洗起来很奇怪,因为 aStream
不是一种数据结构,因此对其进行混洗并没有什么意义(如果您打算构建一个特殊的IntSupplier
)。而是将结果打乱。
As for the performance, while there may be a few overhead, you will still iterate N times in both case and should not really care more.
至于性能,虽然可能会有一些开销,但在这两种情况下你仍然会迭代 N 次,不应该太在意。
回答by Stuart Marks
There are several uses for IntStream.range
.
有多种用途IntStream.range
。
One is to use the int
values themselves:
一种是使用int
值本身:
IntStream.range(start, end).filter(i -> isPrime(i))....
Another is to do something N times:
另一种是做N次某事:
IntStream.range(0, N).forEach(this::doSomething);
Your case (1) is to create an array filled with a range:
您的情况(1)是创建一个填充范围的数组:
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);
There's a utility method Arrays.setAll
that can do this even more concisely:
有一个实用方法Arrays.setAll
可以更简洁地做到这一点:
int[] arr = new int[end - start];
Arrays.setAll(arr, i -> i + start);
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.
还有Arrays.parallelSetAll
哪些可以并行填充现有数组。在内部,它只是使用 anIntStream
并调用parallel()
它。这应该为多核系统上的大型阵列提供加速。
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:
我发现我在 Stack Overflow 上的很多答案都涉及使用IntStream.range
. 您可以在搜索框中使用以下搜索条件搜索它们:
user:1441122 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.
IntStream.range
我发现特别有用的一个应用是对数组元素进行操作,其中数组索引以及数组的值都参与计算。有一整套这样的问题。
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.
例如,假设您要查找数组中增加的数字游程的位置。结果是第一个数组的索引数组,其中每个索引指向运行的开始。
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:
要计算此值,请观察运行从该值小于前一个值的位置开始。(运行也从位置 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]
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.
当然,您可以使用 for 循环来执行此操作,但我发现IntStream
在许多情况下使用更可取。例如,很容易使用 将未知数量的结果存储到数组中toArray()
,而使用 for 循环,您必须处理复制和调整大小,这会分散循环的核心逻辑。
Finally, it's much easier to run IntStream.range
computations in parallel.
最后,IntStream.range
并行运行计算要容易得多。