Java에서 순차 정수 목록 또는 배열을 생성하려면 어떻게해야합니까?


130

를 생성하는 짧고 달콤한 방법이 있나요 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 및 타사 라이브러리를 사용하여 몇 가지 좋은 답변을 받았으므로 모든 솔루션의 성능을 테스트 할 것이라고 생각했습니다.

첫 번째 테스트 [1..10]는 다음 방법을 사용하여 10 개의 요소 목록을 만드는 것을 테스트 합니다.

  • classicArrayList : 내 질문에서 위에 주어진 코드 (그리고 본질적으로 adarshr의 대답과 동일).
  • eclipseCollections : Eclipse Collections 8.0을 사용하여 아래 Donald의 답변에 제공된 코드 .
  • guavaRange : 아래 daveb 의 답변에 제공된 코드 . 기술적으로 이것은 a를 생성하는 List<Integer>것이 아니라 순서대로 ContiguousSet<Integer>구현 Iterable<Integer>하기 때문에 대부분 내 목적에 적합합니다.
  • intStreamRange : 아래 Vladimir의 답변에 제공된 코드 IntStream.rangeClosed()로 Java 8에서 도입 된-를 사용합니다 .
  • streamIterate : Java 8에 도입 된 기능 을 사용하는 아래 Catalin의 답변에 제공된 코드 IntStream입니다.

다음은 목록 크기가 10 인 위의 모든 항목에 대한 초당 킬로 작업 (숫자가 클수록 좋음)의 결과입니다.

목록 생성 처리량

... 그리고 다시 한번 크기가 10,000 인 목록 :

여기에 이미지 설명 입력

마지막 차트는 정확합니다. Eclipse 및 Guava 이외의 솔루션은 너무 느려 단일 픽셀 막대를 얻을 수도 없습니다! 빠른 솔루션은 나머지 솔루션보다 10,000 ~ 20,000 빠릅니다.

물론 여기서 진행되는 것은 구아바와 이클립스 솔루션이 실제로 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입니다.

List <Integer> 반복 (길이 = 10)

... 및 길이 = 10,000 :

List <Integer> 반복 (길이 = 10,000)

많은 요소에 대한 긴 반복은 많은 것을 고르게하지만 일식과 구아바는 10,000 개의 요소 테스트에서도 두 배 이상 빠르게 유지됩니다.

따라서 정말로List<Integer> , eclipse 컬렉션을 원한다면 이클립스 컬렉션이 최선의 선택 인 것처럼 보이지만 물론 더 네이티브 방식으로 스트림을 사용한다면 (예 : .boxed()원시 도메인을 잊어 버리고 축소하는 것) 아마이 모든 것보다 더 빨리 끝날 것입니다. 변형.


1 오류 처리 (예 : end< begin인 경우) 또는 크기가 일부 구현 또는 JVM 제한을 초과하는 경우 (예 : 2^31-1.


아파치 평민, 들어 stackoverflow.com/a/5744861/560302
MoveFast

답변:


185

Java 8을 사용하면 매우 간단하므로 더 이상 별도의 메서드가 필요하지 않습니다.

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

2
위의 답변에 대한 성능 결과를 intStreamRange 레이블로 추가했습니다 .
BeeOnRope

API 24 이상 필요
gcantoni

28

글쎄,이 라이너는 자격이 될 수 있습니다 ( 구아바 범위 사용 )

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

이것은을 만들지 않습니다 List<Integer>,하지만 ContiguousSet구현 특히, 거의 같은 기능을 제공 Iterable<Integer>할 수있는 foreach같은 방법으로 구현 List<Integer>.

구아바 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]

7
나는 asList()당신이 정말로 필요하지 않는 한 거기에서 사용 하지 않을 것입니다 List... ContiguousSet제작자 asSet는 가볍지 만 (범위와 도메인 만 필요합니다) asList()실제로 모든 요소를 ​​메모리에 저장하는 목록을 만듭니다 (현재).
ColinD 2012

1
동의합니다. 영업 그렇지 않으면 내가 그것을 밖으로 떠난 것, 목록 또는 배열 생각을 요청했다
daveb

1
나는 18.0에 대해 믿고 Range있지만 존재하지 않으며 Ranges그들은 asSet방법을 없앴습니다. 내 이전 버전에서는 asSet더 이상 사용되지 않으며 제거 된 것으로 보입니다. 범위는 분명히 연속 컬렉션에만 사용되며 내가이 솔루션을 좋아하지만 적용했습니다.
demongolem

이제 API에 다음과 유사한 코드가 필요합니다. ContiguousSet.create (Range.closed (1, count), DiscreteDomain.integers ()
Ben

위의 답변에 대한 성능 결과를 guavaRange 레이블로 추가했습니다 .
BeeOnRope

11

다음 한 줄짜리 Java 8 버전은 [1, 2, 3 ... 10]을 생성합니다. 의 첫 번째 인수 iterate는 시퀀스의 첫 번째 nr이고 첫 번째 인수 limit는 마지막 숫자입니다.

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

위의 답변에 대한 성능 결과를 streamIterate 레이블로 추가했습니다 .
BeeOnRope

1
설명의 요점으로 limit arg는 마지막 숫자가 아니라 목록의 정수 개수입니다.
neilireson

7

Eclipse CollectionsInterval클래스를 사용할 수 있습니다 .

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

int를 Integers로 사용하는 것을 피하고 싶지만 결과적으로 목록 구조를 원하는 경우 Eclipse Collections에서 IntListwith IntInterval를 사용할 수 있습니다 .

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

IntList이 방법 sum(), min(), minIfEmpty(), max(), maxIfEmpty(), average()median()인터페이스에 사용할 수 있습니다.

명확성을위한 업데이트 : 2017 년 11 월 27 일

An IntervalList<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();

An Interval과 an IntInterval은 동일한 equals계약을 가지고 있지 않습니다 .

Eclipse Collections 9.0 업데이트

이제 기본 스트림에서 기본 컬렉션을 만들 수 있습니다. 있다 withAllofAll환경 설정에 따라 방법. 궁금한 점이 있으면 여기에 둘 다있는 이유를 설명 합니다 . 이러한 메소드는 변경 가능하고 변경 불가능한 Int / Long / Double 목록, 세트, ​​백 및 스택에 존재합니다.

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 컬렉션 커미터입니다.


이 답변에 대한 성능 결과를 eclipseCollections 레이블로 추가했습니다 .
BeeOnRope

산뜻한. 권투를 피해야하는 추가 기본 버전으로 답변을 업데이트했습니다.
Donald Raab

6

이것은 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;  
}

3
당신은 해당 루프를 변경하여 두 개 이상의 문자를 면도 할 수 있습니다 for(int i = begin; i <= end; ret.add(i++));:
vaughandroid

ret.add(i)부분을 ​​for 루프 증분으로 이동 하면 이것이 "더 짧아지는" 지 확실하지 않습니다 . 나는 :)이 짧은 것 한 줄에 모두 쓴 경우 그 논리에 의해 추측
BeeOnRope

@BeeOnRope 예, 확실히 가장 짧은 것은 아니지만 확실히 두 줄로 더 짧습니다. :) 제가 말했듯이, 이것이 Core Java에서 단축 할 수있는 가장 가까운 방법입니다.
adarshr

위의 답변에 대한 성능 결과를 classicArrayList 레이블로 추가했습니다 .
BeeOnRope

3

Guava Ranges를 사용할 수 있습니다.

다음 SortedSet을 사용하여 얻을 수 있습니다.

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

0

이것은 내가 찾을 수있는 가장 짧은 것입니다.

목록 버전

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

-2

이것은 당신을 위해 일할 것입니다 ....

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

AtomicInteger를 사용하는 것은 리소스에 매우 무겁고 테스트에서 약 10 배 느립니다. 그러나 다중 스레드의 경우 안전합니다. end < 확인되지 않은 시작
cl-r

1
AtomicInteger의 사용은 메서드 내에서 의미가 없습니다. 메서드 호출의 모든 문장은 메서드를 호출 한 스레드에 의해 순차적으로 실행되므로 AtomicInteger에서 아무것도 얻지 못하지만 속도가 느려지고 성가신 getAndIncrement () 호출이 발생합니다.
Igor Rodriguez
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.