如何在 Java 中生成连续整数的列表或数组? [英] How can I generate a list or array of sequential integers in Java?

查看:197
本文介绍了如何在 Java 中生成连续整数的列表或数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种简短而甜蜜的方法来生成 List,或者可能是 Integer[]int[],使用从某个 start 值到 end 值的连续值?

也就是说,比以下内容更短但等同于1:

void ListmakeSequence(int 开始,int 结束){列表<整数>ret = new ArrayList<>(end - begin + 1);for (int i=begin; i<=end; i++) {ret.add(i);}返回 ret;}

用番石榴就好.

更新:

性能分析

由于这个问题得到了几个很好的答案,都使用了原生 Java 8 和第三方库,我想我会测试所有解决方案的性能.

第一个测试简单地测试使用以下方法创建一个包含 10 个元素的列表 [1..10]:

  • classicArrayList:上面在我的问题中给出的代码(与 adarshr 的回答基本相同).
  • eclipseCollections:使用 Eclipse Collections 8.0 在下面的

    ...对于大小为 10,000 的列表:

    最后一张图表是正确的 - 除了 Eclipse 和 Guava 之外的其他解决方案都太慢了,甚至无法获得单个像素条!快速解决方案比其他解决方案快 10,000 到 20,000 .

    当然,这里发生的事情是 guava 和 eclipse 解决方案实际上并没有实现任何类型的 10,000 个元素列表 - 它们只是围绕起点和终点的固定大小的包装器.每个元素都是在迭代过程中根据需要创建的.由于我们实际上并未在此测试中进行迭代,因此延迟了成本.所有其他解决方案实际上都在内存中实现了完整列表,并在仅创建基准测试中付出了沉重的代价.

    让我们做一些更现实的事情,并对所有整数进行迭代,对它们求和.所以在 IntStream.rangeClosed 变体的情况下,基准看起来像:

    @Benchmark公共 int intStreamRange() {列表<整数>ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());整数总计 = 0;for (int i : ret) {总计 += i;}总回报;}

    这里,图片变化很大,尽管非物化解决方案仍然是最快的.这里的长度=10:

    ... 长度 = 10,000:

    对许多元素的长时间迭代使事情变得更加平衡,但即使在 10,000 个元素的测试中,eclipse 和 guava 的速度仍然是两倍多.

    所以如果你真的想要一个List,eclipse集合似乎是最好的选择——但当然,如果你以更原生的方式使用流(例如,忘记 .boxed() 并在原始域中进行缩减)您最终可能会比所有这些变体都快.

    <小时>

    1 也许除了错误处理之外,例如,如果 end <begin,或者如果大小超过某些实现或 JVM 限制(例如,数组大于 2^31-1.

    解决方案

    Java 8 非常简单,甚至不再需要单独的方法:

    Listrange = IntStream.rangeClosed(开始,结束).boxed().collect(Collectors.toList());

    Is there a short and sweet way to generate a List<Integer>, or perhaps an Integer[] or int[], with sequential values from some start value to an end value?

    That is, something shorter than, but equivalent to1 the following:

    void List<Integer> makeSequence(int begin, int end) {
      List<Integer> ret = new ArrayList<>(end - begin + 1);
      for (int i=begin; i<=end; i++) {
        ret.add(i);
      }
      return ret;  
    }
    

    The use of guava is fine.

    Update:

    Performance Analysis

    Since this question has received several good answers, both using native Java 8 and third party libraries, I thought I'd test the performance of all the solutions.

    The first test simply tests creating a list of 10 elements [1..10] using the following methods:

    • classicArrayList: the code given above in my question (and essentially the same as adarshr's answer).
    • eclipseCollections: the code given in Donald's answer below using Eclipse Collections 8.0.
    • guavaRange: the code given in daveb's answer below. Technically, this doesn't create a List<Integer> but rather a ContiguousSet<Integer> - but since it implements Iterable<Integer> in-order, it mostly works for my purposes.
    • intStreamRange: the code given in Vladimir's answer below, which uses IntStream.rangeClosed() - which was introduced in Java 8.
    • streamIterate: the code given in Catalin's answer below which also uses IntStream functionality introduced in Java 8.

    Here are the results in kilo-operations per second (higher numbers are better), for all the above with lists of size 10:

    ... and again for lists of size 10,000:

    That last chart is correct - the solutions other than Eclipse and Guava are too slow to even get a single pixel bar! The fast solutions are 10,000 to 20,000 times faster than the rest.

    What's going on here, of course, is that the guava and eclipse solutions don't actually materialize any kind of 10,000 element list - they are simply fixed-size wrappers around the start and endpoints. Each element is created as needed during iteration. Since we don't actually iterate in this test, the cost is deferred. All of the other solutions actually materialize the full list in memory and pay a heavy price in a creation-only benchmark.

    Let's do something a bit more realistic and also iterate over all the integers, summing them. So in the case of the IntStream.rangeClosed variant, the benchmark looks like:

    @Benchmark
    public int intStreamRange() {
        List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());  
    
        int total = 0;
        for (int i : ret) {
            total += i;
        }
        return total;  
    }
    

    Here, the pictures changes a lot, although the non-materializing solutions are still the fastest. Here's length=10:

    ... and length = 10,000:

    The long iteration over many elements evens things up a lot, but eclipse and guava remain more than twice as fast even on the 10,000 element test.

    So if you really want a List<Integer>, eclipse collections seems like the best choice - but of course if you use streams in a more native way (e.g., forgetting .boxed() and doing a reduction in the primitive domain) you'll probably end up faster than all these variants.


    1 Perhaps with the exception of error handling, e.g., if end < begin, or if the size exceeds some implementation or JVM limits (e.g., arrays larger than 2^31-1.

    解决方案

    With Java 8 it is so simple so it doesn't even need separate method anymore:

    List<Integer> range = IntStream.rangeClosed(start, end)
        .boxed().collect(Collectors.toList());
    

    这篇关于如何在 Java 中生成连续整数的列表或数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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