我什么时候应该在Java中使用IntStream.range? [英] When should I use IntStream.range in Java?

查看:754
本文介绍了我什么时候应该在Java中使用IntStream.range?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道何时可以有效地使用 IntStream.range 。我有三个原因,我不确定 IntStream.range 是多么有用。



(请考虑开始和以整数结束。)


  1. 如果我想要一个数组, [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() in IntStream.range(开始,结束).toArray()非常慢。


  2. 我使用MersenneTwister改组数组。 (我在线下载了MersenneTwister课程。)我认为没有办法使用MersenneTwister来洗牌 IntStream


  3. 我认为只需将 int 数字从开始转到 end-1 很有用。我可以使用来表示(int i = start; i< end; i ++),这看起来更容易也不慢。


你能告诉我何时应该选择 IntStream.range

解决方案

IntStream.range 有多种用途。



一个是使用 int 值本身:

  IntStream。范围(开始,结束).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 。您可以在搜索框中使用以下搜索条件搜索它们:

 用户: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 计算要容易得多。 / p>

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.)

  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;
    

    This is probably because toArray() in IntStream.range(start, end).toArray() is very slow.

  2. I use MersenneTwister to shuffle arrays. (I downloaded MersenneTwister class online.) I do not think there is a way to shuffle IntStream using MersenneTwister.

  3. 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.

Could you tell me when I should choose IntStream.range?

解决方案

There are several uses for IntStream.range.

One is to use the int values themselves:

IntStream.range(start, end).filter(i -> isPrime(i))....

Another is to do something N times:

IntStream.range(0, N).forEach(this::doSomething);

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);

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);

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.

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

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.

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]

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.

Finally, it's much easier to run IntStream.range computations in parallel.

这篇关于我什么时候应该在Java中使用IntStream.range?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆