Javaでリストを分割する

Javaでリストをパーティション分割する

1. 概要

このチュートリアルでは、特定のサイズのhow to split a List into several sublistsを説明します。

比較的単純な操作の場合、驚くべきことに、標準のJavaコレクションAPIにはサポートがありません。 幸い、GuavaApache Commons Collectionsの両方が同様の方法で操作を実装しています。

この記事は、例としてここのthe “Java – Back to Basic” seriesの一部です。

参考文献:

Javaでリストを文字列に変換する

さまざまな手法を使用して、リストを文字列に変換する方法を学びます。

Javaでのコレクションのシャッフル

Javaでさまざまなコレクションをシャッフルする方法を学びます。

JavaのSpliteratorの概要

シーケンスのトラバースとパーティション化に使用できるSpliteratorインターフェイスについて説明します。

2. Guavaを使用してリストを分割する

Guavaは、the Lists.partition operationを介して、リストを指定されたサイズのサブリストに分割することを容易にします。

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

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

3. Guavaを使用してコレクションを分割します

Partitioning a CollectionはGuavaでも可能です:

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

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

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

パーティションはsublist views of the original collectionであることに注意してください。これは、元のコレクションの変更がパーティションに反映されることを意味します。

@Test
public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() {
    // Given
    List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List> subSets = Lists.partition(intList, 3);

    // When
    intList.add(9);

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

4. ApacheCommonsCollectionsを使用してリストを分割する

Apache Commons Collectionsの最新リリースでは、リストのパーティション化もrecently addedでサポートされています。

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

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

CommonsCollectionsのGuavaIterables.partitionに似たno corresponding option to partition a raw Collectionがあります。

最後に、ここでも同じ警告が適用されます。結果のパーティションは元のリストのビューです。

5. Java8を使用してリストを分割する

それでは、Java8を使用してリストを分割する方法を見てみましょう。

5.1. コレクターpartitioningBy

次のように、Collectors.partitioningBy()を使用してリストを2つのサブリストに分割できます。

@Test
public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() {
    List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);

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

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

注:結果のパーティションはメインリストのビューではないため、メインリストに変更が加えられてもパーティションには影響しません。

5.2. コレクターgroupingBy

Collectors.groupingBy()を使用して、リストを複数のパーティションに分割することもできます。

@Test
public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() {
    List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);

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

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

注:Collectors.partitioningBy()と同様に、結果のパーティションはメインリストの変更による影響を受けません。

5.3. 区切り文字でリストを分割する

Java8を使用して、リストを区切り記号で分割することもできます。

@Test
public void givenList_whenSplittingBySeparator_thenCorrect() {
    List 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> subSets =
      IntStream.range(0, indexes.length - 1)
               .mapToObj(i -> intList.subList(indexes[i] + 1, indexes[i + 1]))
               .collect(Collectors.toList());

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

注:区切り文字として「0」を使用しました。最初にリスト内のすべての「0」要素のインデックスを取得し、次にこれらのインデックスのListを分割しました。

6. 結論

ここで紹介するソリューションは、追加のライブラリ– GuavaまたはApache Commons Collectionsライブラリを使用します。 これらは両方とも非常に軽量で全体的に非常に便利なので、クラスパスにそれらの1つを置くことは完全に理にかなっています。ただし、それがオプションでない場合– Javaのみのソリューションis shown here

これらすべての例とコードスニペットcan be found over on GitHubの実装–これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。