Post

Java List 분할

1. Partition a List

List를 주어진 크기의 여러 하위 목록으로 분할하는 방법이다.

상대적으로 간단한 작업의 경우 표준 Java 컬렉션 API에서 지원하지 않는다. 운 좋게도 Guava와 Apache Commons Collections 모두 유사한 방식으로 작업을 구현했다.

2. Guava를 사용하여 목록 분할

Guava는 Lists.partition 작업을 통해 List를 지정된 크기의 하위 목록으로 분할하는 것을 용이하게 한다.

1
2
3
4
5
6
7
8
9
10
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);

    List<Integer> lastPartition = subSets.get(2);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
    assertThat(subSets.size(), equalTo(3));
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

3. Guava를 사용하여 컬렉션 분할

Guava를 사용하여 컬렉션을 분할 할 수도 있다.

1
2
3
4
5
6
7
8
9
10
@Test
public void givenCollection_whenParitioningIntoNSublists_thenCorrect() {
    Collection<Integer> intCollection = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);

    Iterable<List<Integer>> subSets = Iterables.partition(intCollection, 3);

    List<Integer> firstPartition = subSets.iterator().next();
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(1, 2, 3);
    assertThat(firstPartition, equalTo(expectedLastPartition));
}

파티션은 원본 컬렉션의 하위 목록 보기이므로 원본 컬렉션의 변경 사항이 파티션에 반영된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() {
    // Given
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);

    // When
    intList.add(9);

    // Then
    List<Integer> lastPartition = subSets.get(2);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8, 9);
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

4. Apache Commons Collections를 사용하여 목록 분할

Apache Commons Collections의 최신 릴리스에는 최근 목록 분할에 대한 지원이 추가되었다.

1
2
3
4
5
6
7
8
9
10
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = ListUtils.partition(intList, 3);

    List<Integer> lastPartition = subSets.get(2);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
    assertThat(subSets.size(), equalTo(3));
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

Commons Collections에는 Guava Iterables.partition과 유사한 원시 컬렉션을 분할하는 해당 옵션이 없다.

마지막으로 동일한 경고가 여기에도 적용된다. 결과 파티션은 원래 목록의 뷰이다.

5. Java8을 사용하여 목록 분할

Java8을 사용하여 목록을 분할하는 방법이다.

1) Collectors partitioningBy

Collectors.partitioningBy()를 사용하여 목록을 2개의 하위 목록으로 나눌 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() {
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);

    Map<Boolean, List<Integer>> groups = 
      intList.stream().collect(Collectors.partitioningBy(s -> s > 6));
    List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());

    List<Integer> lastPartition = subSets.get(1);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
    assertThat(subSets.size(), equalTo(2));
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

참고: 결과 파티션은 기본 목록 보기가 아니므로 기본 목록에 발생하는 모든 변경 사항은 파티션에 영향을 주지 않는다.

2) Collectors groupingBy

Collectors.groupingBy()를 사용하여 목록을 여러 파티션으로 나눌 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() {
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);

    Map<Integer, List<Integer>> groups = 
      intList.stream().collect(Collectors.groupingBy(s -> (s - 1) / 3));
    List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());

    List<Integer> lastPartition = subSets.get(2);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
    assertThat(subSets.size(), equalTo(3));
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

참고: Collectors.partitioningBy()와 마찬가지로 결과 파티션은 기본 목록의 변경 사항에 영향을 받지 않는다.

3) 구분 기호로 목록 분할

Java8을 사용하여 목록을 구분 기호로 나눌 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void givenList_whenSplittingBySeparator_thenCorrect() {
    List<Integer> intList = Lists.newArrayList(1, 2, 3, 0, 4, 5, 6, 0, 7, 8);

    int[] indexes = 
      Stream.of(IntStream.of(-1), IntStream.range(0, intList.size())
      .filter(i -> intList.get(i) == 0), IntStream.of(intList.size()))
      .flatMapToInt(s -> s).toArray();
    List<List<Integer>> subSets = 
      IntStream.range(0, indexes.length - 1)
               .mapToObj(i -> intList.subList(indexes[i] + 1, indexes[i + 1]))
               .collect(Collectors.toList());

    List<Integer> lastPartition = subSets.get(2);
    List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8);
    assertThat(subSets.size(), equalTo(3));
    assertThat(lastPartition, equalTo(expectedLastPartition));
}

참고: “0”을 구분 기호로 사용했다. 먼저 List의 모든 “0” 요소 인덱스를 얻은 다음 이 인덱스에서 List를 분할한다.

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.