Java中整型的短序列

生成一个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; } 

…但是它在逃避我 使用番石榴是好的。

更新:

性能分析

由于这个问题已经得到了几个很好的答案,无论是使用原生Java 8和第三方库,我想我会testing所有解决scheme的性能。

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

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

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

列表创建吞吐量

…并再次列出大小为10,000的列表:

在这里输入图像说明

最后一张图是正确的 – 除Eclipse和Guava以外的解决scheme太慢,甚至没有单个像素栏! 快速解决scheme比其他解决scheme快10,000到20,000

当然,这里的番石榴和日食解决scheme实际上并没有实现任何10,000种元素列表 – 它们仅仅是开始和结束点的固定大小的包装。 每个元素都是在迭代过程中根据需要创build的。 由于我们实际上并没有在这个testing中进行迭代,所以成本是延迟的。 所有其他的解决scheme实际上已经在内存中实现了完整的列表,并且在仅创build的基准中付出了沉重的代价。

让我们做一些更现实的事情,也遍历所有的整数,总结它们。 因此,在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; } 

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

List <Integer>迭代(长度= 10)

…和长度= 10,000:

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

对许多元素的长期迭代使得事情变得很多,但即使在10,000元素testing中,日食和番石榴的速度仍然是两倍以上。

所以,如果你真的想要一个List<Integer> ,eclipse集合看起来是最好的select – 但是当然如果你以更原生的方式使用stream(例如,忘记.boxed()和缩小原始域)可能会比所有这些变种更快。


1也许除了error handling,例如,如果end < begin ,或者如果大小超过了一些实现或JVM限制(例如大于2^31-1数组)。

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

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

那么,这一class轮可能有资格(使用番石榴山脉 )

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

这不会创build一个List<Integer> ,但是ContiguousSet提供了很多相同的function,特别是实现Integer<Integer> ,它允许以与List<Integer>相同的方式实现foreach

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

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

两者都产生:

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

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

您可以使用Eclipse集合中的Interval类。

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

如果你想避免装饰整数作为整数,但仍然喜欢一个列表结构作为结果,那么你可以从Eclipse集合IntList使用IntInterval

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

IntList具有IntList的方法sum()min()minIfEmpty()max()maxIfEmpty()average()median()

注意:我是Eclipse集合的提交者

以下单线程Java 8版本将生成[1,2,3 … 10]。 iterate的第一个参数是序列中的第一个参数, limit的第一个参数是最后一个参数。

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

你可以使用番石榴山脉

你可以通过使用获得一个SortedSet

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

这是我能find的最短的。

列表版本

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

arrays版本

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

这个可能适合你…

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