Short and sweet integer sequence in Java

There should be a short and sweet way to generate a List<Integer> or possibly Integer[] or int[] , with sequential values ​​from some start value to an end value.

That is, the shorter, but equivalent to 1 of the following:

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

... but it evades me. Using guava is fine.

Update:

Performance analysis

Since this question received some good answers, both using native Java 8 and third-party libraries, I decided to check the performance of all solutions.

The first test simply checks the creation of a list of 10 elements [1..10] using the following methods:

  • classicArrayList : the above code in my question (and essentially the same as adarshr address).
  • eclipseCollections : The code provided in Donald's answer below using Eclipse Collections 8.0.
  • guavaRange : daveb code below . Technically, this does not create a List<Integer> , but rather a ContiguousSet<Integer> , but since it implements the Iterable<Integer> in the order, it basically works for my purposes.
  • intStreamRange : the following Vladimir answer below, which uses IntStream.rangeClosed() -, which was introduced in Java 8.
  • streamIterate : the code below , which also uses the IntStream functionality introduced in Java 8.

Below are the results in kilo operations per second (higher numbers are better), for all of the above lists of size 10:

List Creation Performance

... and again for lists of size 10,000:

enter image description here

This last diagram is true - solutions other than Eclipse and Guava are too slow to even get one pixel bar! Quick solutions are 10,000 to 20,000 times faster than the rest.

What happens here, of course, is that the guava and eclipse solutions do not actually materialize a list of 10,000 elements - they are just fixed-size wrappers around the start and end points. Each element is created as needed during iteration. Since we are not actually iterating in this test, the value is delayed. All other solutions actually materialize the complete list in memory and pay a high price in the test just for creation.

Let me do something more realistic, as well as iterate over all integers, summing them up. Therefore, in the case of the IntStream.rangeClosed variant IntStream.rangeClosed benchmark is as follows:

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

Here, the photographs change a lot, although solutions that do not require materialization are still the fastest. Here length = 10:

List <Integer> Iteration (length = 10)

... and length = 10,000:

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

A long iteration over many elements significantly increases the value, but the eclipse and guava remain more than twice as fast even when testing for 10,000 elements.

So, if you really want a List<Integer> , the eclipse collection is probably the best choice, but, of course, if you use streams in a more native way (for example, forgetting .boxed() and making a reduction in a primitive domain), you are probably will be faster than all of these options.




1 Perhaps, with the exception of error handling, for example, if end < begin , or if the size exceeds some implementation limits or JVM (for example, arrays larger than 2^31-1 .

+101
java collections arrays apache-commons guava
Apr 20
source share
8 answers

With Java 8, it is so simple that you no longer need a separate method:

 List<Integer> range = IntStream.rangeClosed(start, end) .boxed().collect(Collectors.toList()); 
+156
Apr 03 '14 at 6:00
source share

Well, this one liner can qualify (uses Guava Ranges )

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

This does not create a List<Integer> , but a ContiguousSet offers the same functionality, in particular the Integer<Integer> implementation, which allows the foreach implementation to be the same as List<Integer> .

In older versions (somewhere before Guava 14) you can use this:

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

Both produce:

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
+26
Apr 20 2018-12-12T00:
source share

The next single-line version of Java 8 will generate [1, 2, 3 ... 10]. The first arg iterate is the first nr in the sequence, and the first arg limit is the last number.

 List<Integer> numbers = Stream.iterate(1, n -> n + 1) .limit(10) .collect(Collectors.toList()); 
+9
Mar 20 '16 at 14:04
source share

This is the shortest I could use with 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; } 
+6
Apr 20 2018-12-12T00:
source share

You can use the Interval class from the Eclipse Collection .

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

The Interval class is lazy, so it does not save all values.

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

Your method will be implemented as follows:

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

If you want to avoid integrating with integer targets as integers, but still look like a list structure, then you can use IntList with IntInterval from the Eclipse collections.

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

IntList has the sum() , min() , minIfEmpty() , max() , maxIfEmpty() , average() and median() methods available on the interface.

Update for clarity: 11/27/2017

An Interval is a List<Integer> , but it is lazy and immutable. This is extremely useful for generating test data, especially if you know a lot about collections. If you want, you can easily copy the interval into a List , Set or Bag as follows:

 Interval integers = Interval.oneTo(10); Set<Integer> set = integers.toSet(); List<Integer> list = integers.toList(); Bag<Integer> bag = integers.toBag(); 

An IntInterval is an ImmutableIntList that continues with IntList . It also has conversion methods.

 IntInterval ints = IntInterval.oneTo(10); IntSet set = ints.toSet(); IntList list = ints.toList(); IntBag bag = ints.toBag(); 

An Interval and IntInterval do not have the same equals contract.

Update for Eclipse Collections 9.0

Now you can create primitive collections from primitive streams. There are withAll and ofAll , depending on your preference. If you're interested, I will explain why we have here . These methods exist for mutable and immutable Int / Long / Double lists, sets, sums, and 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))); 

Note: I am a committer for Eclipse collections

+5
Apr 01 '16 at 7:09
source share

You can use Guava Ranges

You can get SortedSet with

 ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers()); // set contains [2, 3, 4] 
+2
Apr 20 2018-12-12T00:
source share

This is the shortest I could find.

Version list

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

Massive version

 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; } 
0
Apr 20 '12 at 8:28
source share

This might work for you ....

 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; } 
-2
Apr 20 '12 at 8:29
source share



All Articles