java for list a i_如何在Java中生成连续整数的列表或数组?

是否有一种简短而又甜蜜的方法来生成List,或者可能是Integer[]或int[],其顺序值从某个start值到end值?

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

void List makeSequence(int begin, int end) {

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

for (int i=begin; i<=end; i++) {

ret.add(i);

}

return ret;

}

番石榴的使用很好。

更新:

绩效分析

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

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

classicArrayList:上面在我的问题中给出的代码(和adarshr的答案基本相同)。

eclipseCollections:下面使用Eclipse Collections 8.0在Donald的回答中给出的代码。

guavaRange:daveb在下面的答案中给出的代码。从技术上讲,这不会创建List而是ContiguousSet - 但由于它按顺序实现Iterable,因此它主要用于我的目的。

intStreamRange:下面的Vladimir的答案中给出的代码,它使用IntStream.rangeClosed() - 这是在Java 8中引入的。

streamIterate:下面的Catalin答案中给出的代码,它也使用了Java 8中引入的IntStream功能。

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

d958b5f8ef50e732083ccb26c4cf063e.png

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

7254de94fadab586c469eead8a365e2b.png

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

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

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

@Benchmark

public int intStreamRange() {

List ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());

int total = 0;

for (int i : ret) {

total += i;

}

return total;

}

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

311f001c6fc3973d1c9e4b0d38168ee9.png

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

8690325ecf1fdb414a0ccba2139cb1e8.png

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

所以,如果你真的想要一个List,那么eclipse集合似乎是最好的选择 - 当然如果你以更本地的方式使用流(例如,忘记.boxed()并在原始域中进行缩减),你可能会最终比所有这些变种更快。

1也许除了错误处理之外,例如,如果end

对于apache commons,stackoverflow.com / a / 5744861/560302

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

List range = IntStream.rangeClosed(start, end)

.boxed().collect(Collectors.toList());

它应该是IntStream.rangeClosed(...)。

@rewritten,谢谢,你是对的。它在beta版本中被称为rangeInclusive()。

我使用标签intStreamRange为上面的答案添加了性能结果。

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

ContiguousSet integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers());

System.out.println(integerList);

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

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

ImmutableList integerList = Ranges.closedOpen(0, 10).asSet(DiscreteDomains.integers()).asList();

System.out.println(integerList);

两者都产生:

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

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

同意。 OP虽然要求列表或数组,否则我会把它排除在外

我相信18.0,Range存在但不是Ranges,他们已经废除了asSet方法。在我的旧版本中,不推荐使用asSet,并且它们似乎已将其删除。 Ranges显然只是用于连续收藏,虽然我喜欢这个解决方案但他们已经强制执行。

API现在需要类似于此的代码:ContiguousSet.create(Range.closed(1,count),DiscreteDomain.integers()

我使用标签guavaRange为上面的答案添加了性能结果。

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

List numbers = Stream.iterate(1, n -> n + 1)

.limit(10)

.collect(Collectors.toList());

我使用标签streamIterate为上面的答案添加了性能结果。

作为澄清,限制arg不是最后一个数字,它是列表中的整数数。

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

List makeSequence(int begin, int end) {

List ret = new ArrayList(end - begin + 1);

for(int i = begin; i <= end; i++, ret.add(i));

return ret;

}

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

我不确定将ret.add(i)部分移动到for循环增量会使其"更短"。我想按照那种逻辑,如果我把它全部写在一行上它会更短:)

@BeeOnRope是的,绝对不是最短的,但肯定会缩短两行:)正如我所说,这是我们可以在Core Java中缩短它的最接近的地方。

我使用标签classicArrayList为上面的答案添加了性能结果。

您可以使用Eclipse Collections中的Interval类。

List range = Interval.oneTo(10);

range.forEach(System.out::print);  // prints 12345678910

Interval类是惰性的,因此不存储所有值。

LazyIterable range = Interval.oneTo(10);

System.out.println(range.makeString(",")); // prints 1,2,3,4,5,6,7,8,9,10

您的方法可以实现如下:

public List makeSequence(int begin, int end) {

return Interval.fromTo(begin, end);

}

如果你想避免将int打包为Integers,但仍然喜欢列表结构,那么你可以在Eclipse Collections中使用IntList和IntInterval。

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,但它是惰性且不可变的。它对于生成测试数据非常有用,特别是如果您经常处理集合。如果需要,您可以轻松地将间隔复制到List,Set或Bag,如下所示:

Interval integers = Interval.oneTo(10);

Set set = integers.toSet();

List list = integers.toList();

Bag 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合约。

Eclipse Collections 9.0的更新

您现在可以从原始流创建原始集合。根据您的偏好,有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的提交者

我使用标签eclipseCollections为上面的答案添加了性能结果。

整齐。我用一个额外的原始版本更新了我的答案,应避免任何拳击。

你可以使用番石榴山脉

您可以使用获得SortedSet

ImmutableSortedSet set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());

// set contains [2, 3, 4]

这是我能找到的最短的。

列表版本

public List makeSequence(int begin, int end)

{

List ret = new ArrayList(++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 makeSequence(int begin, int end) {

AtomicInteger ai=new AtomicInteger(begin);

List ret = new ArrayList(end-begin+1);

while ( end-->begin) {

ret.add(ai.getAndIncrement());

}

return ret;

}

使用AtomicInteger对于资源非常重,在我的测试中大约慢十倍。但它对于多线程是安全的。结束

使用AtomicInteger在方法中没有意义。方法调用中的所有句子都由调用该方法的线程按顺序运行,因此您无法从AtomicInteger获得任何内容,但会减慢和烦人的getAndIncrement()调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值