1. 序章

[a、b、c、d、e、f] のような配列があり、要素を [[a、b]、[ c、d]、[e、f]]または[[a、b、c]、[d]、[e、f]]

このチュートリアルでは、Kotlinの groupBy、chunked、windowedの違いを調べながらこれを実現します。

2. リストをペアのリストに分割する

この例では、2つのリストを使用します。1つは要素の数が偶数で、もう1つは要素の数が奇数です。

val evenList = listOf(0, "a", 1, "b", 2, "c");
val unevenList = listOf(0, "a", 1, "b", 2, "c", 3);

明らかに、evenListを正確に3つのペアに分割できます。 ただし、unevenListには1つの余分な要素があります。

このセクションの残りの部分では、 unevenList の余分な要素をどのように処理するかなど、2つのリストを分割するためのさまざまな実装について説明します。

2.1. groupByを使用する

まず、g roupByを使用してソリューションを実装しましょう。 昇順の番号でリストを作成し、groupByを使用してそれらを分割します:

val numberList = listOf(1, 2, 3, 4, 5, 6);
numberList.groupBy { (it + 1) / 2 }.values

これにより、望ましい結果が得られます。

[[1, 2], [3, 4], [5, 6]]

それはどのように機能しますか? groupBy は、提供された関数(it + 1)/2をすべての要素で実行します。

  • (1 + 1)/ 2 = 1
  • (2 + 1)/ 2 = 1.5、これは1に丸められます
  • (3 + 1)/ 2 = 2
  • (4 + 1)/ 2 = 2.5、これは2に丸められます
  • (5 + 1)/ 2 = 3
  • (6 + 1)/ 2 = 3.5、これは3に丸められます

次に、 groupBy は、同じ結果が得られたリスト内の要素をグループ化します。

さて、不均一なリストで同じことをすると、次のようになります。

val numberList = listOf(1, 2, 3, 4, 5, 6, 7);
numberList.groupBy { (it + 1) / 2 }.values

すべてのペアと1つの追加要素を取得します。

[[1, 2], [3, 4], [5, 6], [7]]

しかし、さらにいくつかのランダムな数字を使用すると:

val numberList = listOf(1, 3, 8, 20, 23, 30);
numberList.groupBy { (it + 1) / 2 }.values

完全に望ましくないものが得られます。

[[1], [3], [8], [20], [23], [30]]

理由は簡単です。 すべての要素に(it + 1)/ 2 関数を適用すると、 1、2、4、10、12、15が得られます。 すべての結果が異なるため、要素がグループ化されることはありません。

evenListまたはunevenListを使用すると、さらに悪いことになります— [X146X] Strings に関数を適用できないため、コードはコンパイルされません ]。

2.2. groupByおよびwithIndexを使用する

実際、任意のリストをペアにグループ化する場合、関数で値を変更するのではなく、インデックス:を変更します。

evenList.withIndex()
    .groupBy { it.index / 2 }
    .map { it.value.map { it.value } }

これにより、必要なペアのリストが返されます。

[[0, "a"], [1, "b"], [2, "c"]]

さらに、 unevenList を使用すると、別の要素を取得することもできます。

[[0, "a"], [1, "b"], [2, "c"], [3]]

2.3. groupByfoldIndexedの使用

index を使用するだけでなく、 foldIndexed を使用してもう少しプログラムして、割り当てを節約することもできます。

evenList.foldIndexed(ArrayList<ArrayList<Any>>(evenList.size / 2)) { index, acc, item ->
    if (index % 2 == 0) {
        acc.add(ArrayList(2))
    }
    acc.last().add(item)
    acc
}

もう少し冗長ですが、 foldIndexedソリューションは各要素に対して操作を実行するだけですが、withIndex関数は最初にイテレーターを作成して各要素をラップします。

2.4. チャンクを使用

しかし、チャンクを使用すると、これをよりエレガントに行うことができます。では、このメソッドをevenListに適用しましょう。

evenList.chunked(2)

evenList は、必要なペアを提供します。

[[0, "a"], [1, "b"], [2, "c"]]

unevenList はペアと追加の要素を提供しますが、

[[0, "a"], [1, "b"], [2, "c"], [3]]

2.5. windowedを使用する

また、チャンクは非常にうまく機能しますが、もう少し制御が必要な場合もあります。

たとえば、ペアのみが必要かどうか、または追加の要素を含めるかどうかを指定する必要がある場合があります。 windowedメソッドは、partialWindows Boolean を提供します。これは、部分的な結果が必要かどうかを示します。

デフォルトでは、partialWindowsfalseです。 したがって、次のステートメントは同じ結果を生成します。

evenList.windowed(2, 2)
unevenList.windowed(2, 2, false)

どちらも、個別の要素なしでリストを返します。

[[0, "a"], [1, "b"], [2, "c"]]

最後に、partialWindowstrueに設定して、部分的な結果を含めると、次のようになります。

unevenList.windowed(2, 2, true)

ペアのリストと個別の要素を取得します。

[[0, "a"], [1, "b"], [2, "c"], [3]]

3. 結論

groupBy の使用は優れたプログラミング演習ですが、エラーが発生しやすくなります。 一部のエラーは、indexを使用するだけで解決できます。

コードを最適化するために、foldIndexedを使用することもできます。 ただし、これによりさらに多くのコードが生成されます。 幸い、チャンクメソッドは、すぐに使用できる同じ機能を提供します。

さらに、 windowed メソッドは、追加の構成オプションを提供します。 可能であれば、チャンク方式を使用するのが最善であり、追加の構成が必要な場合は、ウィンドウ方式を使用する必要があります。

いつものように、完全なソースコードはGitHubで入手できます。