1. 概要

このクイックチュートリアルでは、KotlinのCollections APIを紹介し、Kotlinのさまざまなコレクションタイプとコレクションの一般的な操作について説明します。

2. コレクション対。 可変コレクション

まず、Kotlinのさまざまな種類のコレクションを見てみましょう。 コレクションの基本的なタイプを初期化する方法を見ていきます。

Collection インターフェースは読み取り専用メソッドをサポートし、MutableCollectionは読み取り/書き込みメソッドをサポートします。

2.1. リスト

メソッドlistOf()を使用して単純な読み取り専用 List を作成し、 mutableListOf()を使用して読み取り/書き込みMutableListを作成できます。

val theList = listOf("one", "two", "three")    

val theMutableList = mutableListOf("one", "two", "three")

2.2. セット

同様に、メソッド setOf()を使用して読み取り専用 Set を作成し、 mutableSetOf()を使用して読み取り/書き込みMutableSetを作成できます。

val theSet = setOf("one", "two", "three")  

val theMutableSet = mutableSetOf("one", "two", "three")

2.3. マップ

メソッドmapOf()を使用して読み取り専用 Map を作成し、 mutableMapOf()を使用して読み取り/書き込みMutableMapを作成することもできます。

val theMap = mapOf(1 to "one", 2 to "two", 3 to "three")

val theMutableMap = mutableMapOf(1 to "one", 2 to "two", 3 to "three")

3. 便利な演算子

KotlinのCollectionsAPIは、Javaで見つけることができるものよりもはるかに豊富で、オーバーロードされた演算子のセットが付属しています。

3.1. 「in」演算子

collection.contains(x)に変換できる式「 xincollection」を使用できます。

@Test
fun whenSearchForExistingItem_thenFound () {
    val theList = listOf("one", "two", "three")

    assertTrue("two" in theList)        
}

3.2. “ +”演算子

「+」演算子を使用して、要素またはコレクション全体を別の要素に変換できます。

@Test
fun whenJoinTwoCollections_thenSuccess () {
    val firstList = listOf("one", "two", "three")
    val secondList = listOf("four", "five", "six")
    val resultList = firstList + secondList

    assertEquals(6, resultList.size)   
    assertTrue(resultList.contains("two"))        
    assertTrue(resultList.contains("five"))        
}

3.3. “-“演算子

同様に、「-」演算子を使用して1つまたは複数の要素を削除できます。

@Test
fun whenExcludeItems_thenRemoved () {
    val firstList = listOf("one", "two", "three")
    val secondList = listOf("one", "three")
    val resultList = firstList - secondList

    assertEquals(1, resultList.size)        
    assertTrue(resultList.contains("two"))        
}

4. その他の方法

最後に、収集のためのいくつかの一般的な方法を探ります。 Javaでは、高度なメソッドを活用する場合は、 StreamAPIを使用する必要があります。

Kotlinでは、CollectionsAPIで利用可能な同様のメソッドを見つけることができます。

4.1. スライス

指定されたリストからサブリストを取得できます:

@Test
fun whenSliceCollection_thenSuccess () {
    val theList = listOf("one", "two", "three")
    val resultList = theList.slice(1..2)

    assertEquals(2, resultList.size)        
    assertTrue(resultList.contains("two"))        
}

4.2. 削除

リストからすべてのnullを簡単に削除できます:

@Test
fun whenFilterNullValues_thenSuccess () {
    val theList = listOf("one", null, "two", null, "three")
    val resultList = theList.filterNotNull()

    assertEquals(3, resultList.size)        
}

4.3. フィルタリング

フィルタ()、を使用してコレクションアイテムを簡単にフィルタリングできます。これは、Java Stream APIのfilter()メソッドと同様に機能します。

@Test
fun whenFilterNonPositiveValues_thenSuccess () {
    val theList = listOf(1, 2, -3, -4, 5, -6)
    val resultList = theList.filter{ it > 0}

    assertEquals(3, resultList.size)  
    assertTrue(resultList.contains(1))
    assertFalse(resultList.contains(-4))      
}

4.4. ドロップ

最初のN個のアイテムをドロップできます。

@Test
fun whenDropFirstItems_thenRemoved () {
    val theList = listOf("one", "two", "three", "four")
    val resultList = theList.drop(2)

    assertEquals(2, resultList.size)        
    assertFalse(resultList.contains("one"))        
    assertFalse(resultList.contains("two"))        
}

与えられた条件を満たす場合、最初のいくつかのアイテムを削除できます。

@Test
fun whenDropFirstItemsBasedOnCondition_thenRemoved () {
    val theList = listOf("one", "two", "three", "four")
    val resultList = theList.dropWhile{ it.length < 4 }

    assertEquals(2, resultList.size)        
    assertFalse(resultList.contains("one"))        
    assertFalse(resultList.contains("two"))        
}

4.5. グループ化

要素をグループ化できます。

@Test
fun whenGroupItems_thenSuccess () {
    val theList = listOf(1, 2, 3, 4, 5, 6)
    val resultMap = theList.groupBy{ it % 3}

    assertEquals(3, resultMap.size)  
    
    assertTrue(resultMap[1]!!.contains(1))
    assertTrue(resultMap[2]!!.contains(5))      
}

4.6. マッピング

提供されている関数を使用して、すべての要素をマップできます。

@Test
fun whenApplyFunctionToAllItems_thenSuccess () {
    val theList = listOf(1, 2, 3, 4, 5, 6)
    val resultList = theList.map{ it * it }
    
    assertEquals(4, resultList[1])
    assertEquals(9, resultList[2])
}

flatMap()を使用して、ネストされたコレクションをフラット化できます。 ここでは、変換しています文字列 Lへ ist で終わることを避けますリスト >>

@Test
fun whenApplyMultiOutputFunctionToAllItems_thenSuccess () {
    val theList = listOf("John", "Tom")
    val resultList = theList.flatMap{ it.toLowerCase().toList() }
    
    assertEquals(7, resultList.size)
}

4.7. 割引

fold /reduce操作を実行できます。

@Test
fun whenApplyFunctionToAllItemsWithStartingValue_thenSuccess () {
    val theList = listOf(1, 2, 3, 4, 5, 6)
    val finalResult = theList.fold(0, {acc, i -> acc + (i * i)})
    
    assertEquals(91, finalResult)
}

4.8. チャンキング

コレクションを特定のサイズのチャンクに分割するには、 branched()メソッドを使用できます。

@Test
fun whenApplyingChunked_thenShouldBreakTheCollection() {
    val theList = listOf(1, 2, 3, 4, 5)
    val chunked = theList.chunked(2)

    assertThat(chunked.size).isEqualTo(3)
    assertThat(chunked.first()).contains(1, 2)
    assertThat(chunked[1]).contains(3, 4)
    assertThat(chunked.last()).contains(5)
}

コレクションには5つの要素があるため、 branched(2)メソッド呼び出しは、それぞれ2つの要素と1つの単一要素のコレクションを持つ2つのコレクションを返します。

コレクションを分割した後、各チャンクを別のチャンクにマップすることもできます。

@Test
fun whenApplyingChunkedWithTransformation_thenShouldBreakTheCollection() {
    val theList = listOf(1, 2, 3, 4, 5)
    val chunked = theList.chunked(3) { it.joinToString(", ") }

    assertThat(chunked.size).isEqualTo(2)
    assertThat(chunked.first()).isEqualTo("1, 2, 3")
    assertThat(chunked.last()).isEqualTo("4, 5")
}

サイズ3のチャンクを作成した後、各チャンクをコンマ区切りの文字列に変換します。

4.9. ウィンドウ処理

windowed()関数は、指定されたサイズのスライディングウィンドウを要素のコレクション上で移動することにより、要素範囲のリストを返します。

これをよりよく理解するために、 windowed(3)が6つの要素のコレクションでどのように機能するかを見てみましょう。

最初、ウィンドウサイズは3であるため、最初のリストには1、2、および3が含まれます。 次に、スライディングウィンドウは1つの要素をさらに移動します。

スライディングウィンドウは、指定されたサイズの別のリストの作成に失敗するまで前方に移動します。

この一連の遷移は、Kotlinコードで次のように現れます。

@Test
fun whenApplyingWindowed_thenShouldCreateSlidingWindowsOfElements() {
    val theList = (1..6).toList()
    val windowed = theList.windowed(3)

    assertThat(windowed.size).isEqualTo(4)
    assertThat(windowed.first()).contains(1, 2, 3)
    assertThat(windowed[1]).contains(2, 3, 4)
    assertThat(windowed[2]).contains(3, 4, 5)
    assertThat(windowed.last()).contains(4, 5, 6)
}

デフォルトでは、スライディングウィンドウは毎回さらに1ステップ移動します。 もちろん、カスタムステップ値を渡すことでこれを変更できます。

@Test
fun whenApplyingWindowedWithTwoSteps_thenShouldCreateSlidingWindowsOfElements() {
    val theList = (1..6).toList()
    val windowed = theList.windowed(size = 3, step = 2)

    assertThat(windowed.size).isEqualTo(2)
    assertThat(windowed.first()).contains(1, 2, 3)
    assertThat(windowed.last()).contains(3, 4, 5)
}

windowed()関数は、デフォルトでは、常に、指定されたサイズの範囲のみを作成します。 これを変更するには、partialWindowsパラメーターをtrueに設定します。

@Test
fun whenApplyingPartialWindowedWithTwoSteps_thenShouldCreateSlidingWindowsOfElements() {
    val theList = (1..6).toList()
    val windowed = theList.windowed(size = 3, step = 2, partialWindows = true)

    assertThat(windowed.size).isEqualTo(3)
    assertThat(windowed.first()).contains(1, 2, 3)
    assertThat(windowed[1]).contains(3, 4, 5)
    assertThat(windowed.last()).contains(5, 6)
}

chunked()関数と同様に、各範囲を別の範囲にマップすることができます。

@Test
fun whenApplyingTransformingWindows_thenShouldCreateSlidingWindowsOfElements() {
    val theList = (1..6).toList()
    val windowed = theList.windowed(size = 3, step = 2, partialWindows = true) { it.joinToString(", ") }

    assertThat(windowed.size).isEqualTo(3)
    assertThat(windowed.first()).isEqualTo("1, 2, 3")
    assertThat(windowed[1]).isEqualTo("3, 4, 5")
    assertThat(windowed.last()).isEqualTo("5, 6")
}

5. 結論

KotlinのCollectionsAPIといくつかの最も興味深いメソッドを調査しました。

そして、いつものように、完全なソースコードはGitHubでにあります。