[英]How can I generate a list or array of sequential integers in 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 和第三方库,我想我会测试所有解决方案的性能。
第一个测试简单地测试使用以下方法创建一个包含 10 个元素的列表[1..10]
:
List<Integer>
而是创建ContiguousSet<Integer>
- 但由于它按顺序实现Iterable<Integer>
,它主要适用于我的目的。IntStream.rangeClosed()
- 它是在 Java 8 中引入的。IntStream
功能。以下是每秒千次操作的结果(数字越大越好),对于上述所有大小为 10 的列表:
...再次对于大小为 10,000 的列表:
最后一张图表是正确的 - 除了 Eclipse 和 Guava 之外的解决方案太慢了,甚至无法获得单个像素条! 快速解决方案比其他解决方案快 10,000 到 20,000倍。
当然,这里发生的事情是 guava 和 eclipse 解决方案实际上并没有实现任何类型的 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;
}
在这里,图片变化很大,尽管非实体化解决方案仍然是最快的。 这里的长度= 10:
...和长度 = 10,000:
对许多元素的长时间迭代使事情变得更加平衡,但即使在 10,000 个元素的测试中,eclipse 和 guava 的速度仍然是两倍多。
所以如果你真的想要一个List<Integer>
,eclipse 集合似乎是最好的选择 - 但当然,如果你以更原生的方式使用流(例如,忘记.boxed()
并减少原始域)你'最终可能会比所有这些变体都快。
1也许除了错误处理,例如,如果end
< begin
,或者如果大小超过某些实现或 JVM 限制(例如,数组大于2^31-1
。
使用 Java 8,它非常简单,因此它甚至不再需要单独的方法:
List<Integer> range = IntStream.rangeClosed(start, end)
.boxed().collect(Collectors.toList());
嗯,这个班轮可能符合条件(使用番石榴范围)
ContiguousSet<Integer> integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers());
System.out.println(integerList);
这不会创建List<Integer>
,但ContiguousSet
提供了许多相同的功能,特别是实现Iterable<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]
以下单行 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());
您可以使用Eclipse Collections 中的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);
}
如果你想避免拳击整数为整数,但仍像一个表结构的结果,那么你可以使用IntList
与IntInterval
从Eclipse的集合。
public IntList makeSequence(int begin, int end) {
return IntInterval.fromTo(begin, end);
}
IntList
具有方法sum()
min()
minIfEmpty()
max()
maxIfEmpty()
average()
和median()
的接口上可用。
更新为清晰:11/27/2017
Interval
是一个List<Integer>
,但它是惰性且不可变的。 它对于生成测试数据非常有用,尤其是当您处理大量集合时。 如果您愿意,您可以轻松地将间隔复制到List
、 Set
或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
没有相同的equals
合同。
您现在可以从原始流创建原始集合。 根据您的喜好,有withAll
和ofAll
方法。 如果你很好奇,我会解释为什么我们这里都有。 这些方法适用于可变和不可变的 Int/Long/Double Lists、Sets、Bags 和 Stacks。
Assert.assertEquals(
IntInterval.oneTo(10),
IntLists.mutable.withAll(IntStream.rangeClosed(1, 10)));
Assert.assertEquals(
IntInterval.oneTo(10),
IntLists.immutable.withAll(IntStream.rangeClosed(1, 10)));
注意:我是 Eclipse Collections 的提交者
这是我使用 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;
}
你可以使用番石榴范围
您可以通过使用获得SortedSet
ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());
// set contains [2, 3, 4]
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);
这是我能找到的最短的。
列表版本
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;
}
这个可能对你有用......
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.