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的答案中给出的代码。
- guavaRange : daveb在下面的答案给出的代码。 从技术上讲,这不会创build一个
List<Integer>
而是创build一个ContiguousSet<Integer>
– 但是由于它实现了Iterable<Integer>
,所以它主要用于我的目的。 - intStreamRange :在下面的Vladimir的答案中给出的代码,它使用
IntStream.rangeClosed()
– 它是在Java 8中引入的。 - streamIterate :在Catalin的答案中给出的代码也使用了Java 8中引入的
IntStream
function。
以下是每秒千次操作的结果(更高的数字更好),以上所有的大小为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:
…和长度= 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; }