如何在Java中生成连续整数的列表或数组?

Bee*_*ope 105 java arrays collections apache-commons guava

是否有一种简短而甜蜜的方式来生成一个List<Integer>或者一个 Integer[]或者int[]从某个start值到end值的连续值?

也就是说,短于,但相当于以下1:

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;  
}
Run Code Online (Sandbox Code Playgroud)

番石榴的使用很好.

更新:

绩效分析

由于这个问题已经收到了几个很好的答案,无论是使用本机Java 8还是第三方库,我都认为我会测试所有解决方案的性能.

第一个测试只是[1..10]使用以下方法测试创建10个元素的列表:

  • classicArrayList:上面在我的问题中给出的代码(和adarshr的答案基本相同).
  • eclipseCollections:下面使用Eclipse Collections 8.0 在Donald的回答中给出的代码.
  • guavaRange:daveb下面的答案中给出的代码.从技术上讲,这不是创造一个List<Integer>而是创造一个ContiguousSet<Integer>- 但由于它Iterable<Integer>按顺序实现,它主要用于我的目的.
  • intStreamRange:下面的Vladimir的答案中给出的代码,它使用了IntStream.rangeClosed()- 这是在Java 8中引入的.
  • streamIterate:下面的Catalin答案中给出的代码,它也使用IntStream了Java 8中引入的功能.

以下是每秒千位操作的结果(更高的数字更好),对于以上所有的大小为10的列表:

列表创建吞吐量

......再次列出10,000的清单:

在此输入图像描述

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

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

让我们做一些更现实的事情,并迭代所有整数,总结它们.因此,在IntStream.rangeClosed变体的情况下,基准测试看起来像:

@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;  
}
Run Code Online (Sandbox Code Playgroud)

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

列表<整数>迭代(长度= 10)

......和长度= 10,000:

列表<整数>迭代(长度= 10,000)

对许多元素进行的长时间迭代使得事情变得非常均衡,但即使在10,000元素测试中,日食和番石榴的速度仍然快了两倍多.

因此,如果你真的想要一个List<Integer>,eclipse集合似乎是最好的选择 - 当然如果你以更原生的方式使用流(例如,忘记.boxed()并减少原始域)你可能会比所有这些更快变种.


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

Vla*_*eev 163

使用Java 8它非常简单,因此它甚至不再需要单独的方法:

List<Integer> range = IntStream.rangeClosed(start, end)
    .boxed().collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 需要 API 24+ (4认同)
  • 它应该是`IntStream.rangeClosed(...)`. (3认同)
  • 我使用标签 **intStreamRange** 添加了上面这个答案的性能结果。 (2认同)
  • 例如@FelixJassler `IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList())`。 (2认同)

dav*_*veb 26

嗯,这个班轮可能符合条件(使用番石榴山脉)

    ContiguousSet<Integer> integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers());
    System.out.println(integerList);
Run Code Online (Sandbox Code Playgroud)

这不会创建List<Integer>,但ContiguousSet提供相同的功能,特别是实现Iterable<Integer>允许foreach以相同的方式实现List<Integer>.

在旧版本(Guava 14之前的某个地方),你可以使用它:

    ImmutableList<Integer> integerList = Ranges.closedOpen(0, 10).asSet(DiscreteDomains.integers()).asList();
    System.out.println(integerList);
Run Code Online (Sandbox Code Playgroud)

两者都产生:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Run Code Online (Sandbox Code Playgroud)

  • 我不会在那里使用`asList()`除非你真的需要`List` ...`asSet`生成的`ContiguousSet`是轻量级的(它只需要范围和域),但是`asList()`将创建一个实际存储内存中所有元素的列表(当前). (7认同)

小智 9

以下单行Java 8版本将生成[1,2,3 ... 10].第一个arg iterate是序列中的第一个nr,第一个arg limit是最后一个数字.

List<Integer> numbers = Stream.iterate(1, n -> n + 1)
                              .limit(10)
                              .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 作为澄清的一点,限制 arg 不是最后一个数字,它是列表中整数的数量。 (2认同)

ada*_*shr 6

这是我使用Core Java最短的时间.

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;  
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以通过将循环更改为`for(int i = begin; i <= end; ret.add(i ++));`:)来减少几个字符. (3认同)

Don*_*aab 6

您可以使用Eclipse Collections中Interval类。

List<Integer> range = Interval.oneTo(10);
range.forEach(System.out::print);  // prints 12345678910
Run Code Online (Sandbox Code Playgroud)

Interval班是懒惰的,所以不存储所有的值。

LazyIterable<Integer> range = Interval.oneTo(10);
System.out.println(range.makeString(",")); // prints 1,2,3,4,5,6,7,8,9,10
Run Code Online (Sandbox Code Playgroud)

您的方法将可以按以下方式实现:

public List<Integer> makeSequence(int begin, int end) {
    return Interval.fromTo(begin, end);
}
Run Code Online (Sandbox Code Playgroud)

如果您希望避免将整数作为Integers装箱,但仍希望使用列表结构,则可以使用Eclipse Collections中的IntListwith IntInterval

public IntList makeSequence(int begin, int end) {
    return IntInterval.fromTo(begin, end);
}
Run Code Online (Sandbox Code Playgroud)

IntList有方法sum()min()minIfEmpty()max()maxIfEmpty()average()median()可用的接口。

为清楚起见更新:2017年11月27日

An Interval是一个List<Integer>,但是它是惰性的并且是不变的。这对于生成测试数据非常有用,尤其是在您处理大量集合时。如果你愿意,你可以在一个时间间隔轻松复制到ListSetBag如下:

Interval integers = Interval.oneTo(10);
Set<Integer> set = integers.toSet();
List<Integer> list = integers.toList();
Bag<Integer> bag = integers.toBag();
Run Code Online (Sandbox Code Playgroud)

An IntIntervalImmutableIntList延伸的IntList。它还具有转换器方法。

IntInterval ints = IntInterval.oneTo(10);
IntSet set = ints.toSet();
IntList list = ints.toList();
IntBag bag = ints.toBag();
Run Code Online (Sandbox Code Playgroud)

An Interval和an IntInterval没有相同的equals合同。

Eclipse Collections 9.0的更新

现在,您可以从原始流创建原始集合。有withAllofAll方法取决于您的喜好。如果您很好奇,请解释为什么我们都在这里。这些方法适用于可变且不变的Int / Long / Double列表,集合,袋子和堆栈。

Assert.assertEquals(
        IntInterval.oneTo(10),
        IntLists.mutable.withAll(IntStream.rangeClosed(1, 10)));

Assert.assertEquals(
        IntInterval.oneTo(10),
        IntLists.immutable.withAll(IntStream.rangeClosed(1, 10)));
Run Code Online (Sandbox Code Playgroud)

注意:我是Eclipse Collections的提交者