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

时间:2012-04-20 07:59:18

标签: java arrays collections guava apache-commons

是否有一种简短而又甜蜜的方式来生成List<Integer>,或者Integer[]int[],其中包含从start值到{{1}的连续值值?

即,短于,但相当于 1 以下内容:

end

番石榴的使用很好。

更新

绩效分析

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

第一个测试只是使用以下方法测试创建10个元素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; } 的列表:

  • classicArrayList :我在问题中给出的代码(与adarshr的答案基本相同)。
  • eclipseCollections :使用Eclipse Collections 8.0在Donald's answer下面给出的代码。
  • guavaRange :以下daveb's answer中提供的代码。从技术上讲,这不会创建[1..10],而是创建List<Integer> - 但由于它按顺序实现ContiguousSet<Integer>,因此它主要用于我的目的。
  • intStreamRange :下面Vladimir's answer中给出的代码,它使用Iterable<Integer> - 这是Java 8中引入的。
  • streamIterate :下面Catalin's answer中给出的代码,该代码也使用了Java 8中引入的IntStream.rangeClosed()功能。

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

List creation throughput

...再次查看大小为10,000的列表:

enter image description here

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

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

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

IntStream.rangeClosed

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

List<Integer> Iteration (length=10)

...和长度= 10,000:

List<Integer> Iteration (length=10,000)

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

因此,如果你真的想要一个@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; } ,那么eclipse集合似乎是最好的选择 - 但当然如果你以更本地的方式使用流(例如,忘记{{1}并且在原始域中进行减少)你可能最终会比所有这些变体更快。


1 也许除错误处理外,例如List<Integer>&lt; .boxed(),或者大小超过某些实现或JVM限制(例如,大于end的数组。

9 个答案:

答案 0 :(得分:133)

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

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

答案 1 :(得分:26)

嗯,这一个班轮可能符合条件(使用Guava Ranges

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

这不会创建List<Integer>,但ContiguousSet提供了相同的功能,特别是实现Integer<Integer>,允许foreach以与{{{1}相同的方式实现1}}。

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

List<Integer>

两者都产生:

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

答案 2 :(得分:7)

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

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

答案 3 :(得分:5)

这是我使用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;  
}

答案 4 :(得分:5)

您可以使用Interval中的Eclipse Collections课程。

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

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

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

您的方法可以按如下方式实施:

public List<Integer> makeSequence(int begin, int end) {
    return Interval.fromTo(begin, end);
}

如果你想避免将int打成整数,但仍然喜欢列表结构,那么你可以在Eclipse Collections中使用IntListIntInterval

public IntList makeSequence(int begin, int end) {
    return IntInterval.fromTo(begin, end);
}

IntList包含方法sum()min()minIfEmpty()max()maxIfEmpty()average()和{{1}在接口上可用。

更新清晰度:11/27/2017

median()Interval,但它是懒惰且不可变的。它对于生成测试数据非常有用,特别是如果您经常处理集合。如果您愿意,可以轻松地将时间间隔复制到List<Integer>ListSet,如下所示:

Bag

Interval integers = Interval.oneTo(10); Set<Integer> set = integers.toSet(); List<Integer> list = integers.toList(); Bag<Integer> bag = integers.toBag(); IntInterval,其扩展为ImmutableIntList。它还有转换器方法。

IntList

IntInterval ints = IntInterval.oneTo(10); IntSet set = ints.toSet(); IntList list = ints.toList(); IntBag bag = ints.toBag(); Interval没有相同的IntInterval合同。

更新Eclipse Collections 9.0

您现在可以从原始流创建原始集合。根据您的偏好,有equalswithAll方法。如果你很好奇,我会解释为什么我们都有here。这些方法适用于可变和不可变的Int / Long / Double Lists,Sets,Bags和Stacks。

ofAll

注意:我是Eclipse Collections的提交者

答案 5 :(得分:2)

您可以使用Guava Ranges

您可以使用

获得SortedSet
ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());
// set contains [2, 3, 4]

答案 6 :(得分:1)

int[] arr = IntStream.rangeClosed(2, 5).toArray();
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 5]

Integer[] boxedArr = IntStream.rangeClosed(2, 5)
  .boxed().toArray(Integer[]::new);
System.out.println(Arrays.toString(boxedArr));

// Since Java 16
List<Integer> list1 = IntStream.rangeClosed(2, 5)
  .boxed().toList();
System.out.println(list1);

List<Integer> list2 = IntStream.rangeClosed(2, 5)
  .boxed().collect(Collectors.toList());
System.out.println(list2);

List<Integer> list3 = Arrays.asList(boxedArr);
System.out.println(list3);

List<Integer> list4 = new ArrayList<>();
IntStream.rangeClosed(2, 5).forEachOrdered(list4::add);
System.out.println(list4);

答案 7 :(得分:0)

这是我能找到的最短的。

列出版本

public List<Integer> makeSequence(int begin, int end)
{
    List<Integer> ret = new ArrayList<Integer>(++end - begin);

    for (; begin < end; )
        ret.add(begin++);

    return ret;
}

数组版本

public int[] makeSequence(int begin, int end)
{
    if(end < begin)
        return null;

    int[] ret = new int[++end - begin];
    for (int i=0; begin < end; )
        ret[i++] = begin++;
    return ret;
}

答案 8 :(得分:-2)

这个可能对你有用....

void List<Integer> makeSequence(int begin, int end) {

  AtomicInteger ai=new AtomicInteger(begin);
  List<Integer> ret = new ArrayList(end-begin+1);

  while ( end-->begin) {

    ret.add(ai.getAndIncrement());

  }
  return ret;  
}