Nic*_*kel 34 java java-8 java-stream
我想知道何时可以IntStream.range有效使用.我有三个原因,我不确定它有多大用处IntStream.range.
(请将开头和结尾视为整数.)
如果我想要一个数组,[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;
Run Code Online (Sandbox Code Playgroud)
这可能是因为toArray()在IntStream.range(start, end).toArray()非常缓慢.
我使用MersenneTwister来重排数组.(我在网上下载了MersenneTwister课程.)我认为没有办法IntStream使用MersenneTwister 进行随机播放.
我不认为刚开int从数字start到end-1是很有用的.我可以使用for(int i = start; i < end; i++),这似乎更容易,而不是慢.
你能告诉我什么时候应该选择IntStream.range吗?
Stu*_*rks 26
有几种用途IntStream.range.
一个是使用int值本身:
IntStream.range(start, end).filter(i -> isPrime(i))....
Run Code Online (Sandbox Code Playgroud)
另一个是做N次:
IntStream.range(0, N).forEach(this::doSomething);
Run Code Online (Sandbox Code Playgroud)
你的情况(1)是创建一个充满范围的数组:
int[] arr = IntStream.range(start, end).toArray();
Run Code Online (Sandbox Code Playgroud)
你说这是"非常慢"但是,和其他受访者一样,我怀疑你的基准测试方法.对于小型阵列,流设置确实有更多的开销,但这应该是如此之小以至于不可察觉.对于大型阵列,开销应该可以忽略不计,因为填充大型阵列主要是内存带宽.
有时您需要填充现有数组.你可以这样做:
int[] arr = new int[end - start];
IntStream.range(0, end - start).forEach(i -> arr[i] = i + start);
Run Code Online (Sandbox Code Playgroud)
有一种实用方法Arrays.setAll可以更简洁地做到这一点:
int[] arr = new int[end - start];
Arrays.setAll(arr, i -> i + start);
Run Code Online (Sandbox Code Playgroud)
还Arrays.parallelSetAll可以并行填充现有阵列.在内部,它只是使用IntStream并调用parallel()它.这应该为多核系统上的大阵列提供加速.
我发现我在Stack Overflow上的相当多的答案都涉及到使用IntStream.range.您可以在搜索框中使用以下搜索条件搜索它们:
user:1441122 IntStream.range
Run Code Online (Sandbox Code Playgroud)
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]
Run Code Online (Sandbox Code Playgroud)
当然,您可以使用for循环执行此操作,但我发现IntStream在许多情况下使用是更可取的.例如,很容易将未知数量的结果存储到数组中toArray(),而使用for循环则必须处理复制和调整大小,这会分散循环的核心逻辑.
最后,IntStream.range并行运行计算要容易得多.
这是一个例子:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
那么,让我们看看sum()它是做什么的:它计算任意数字流的总和.我们用两种不同的方式来称呼它:一次是明确的数字列表,一次是一个范围.
如果你只有call A,你可能会想把这两个数字放到一个数组中并传递给它,sum()但这显然不是一个选项call B(你的内存不足).同样,你可以通过开始和结束call B,但是你不能支持的情况call A.
总而言之,范围在这里很有用,因为:
还有可读性参数:使用流的代码可以比循环更简洁,因此更具可读性,但我想展示一个示例,其中依赖于IntStreans 的解决方案在功能上也更优越.
我曾经LongStream强调过这一点,但同样如此IntStream
是的,对于简单的求和,这可能看起来有点过分,但考虑例如水库采样
IntStream.range将一个整数范围作为流返回,以便您可以对其进行流处理.
喜欢占据每个元素的正方形
IntStream.range(1, 10).map(i -> i * i);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
25813 次 |
| 最近记录: |