🔖

[Kotlin]Collection操作を8つの分類で解説①transformation

2024/03/19に公開

Collection operations: コレクションの操作

少々前に、"Collectionとは"という内容で、
Kotlin: Collectionを理解したい!IteratorについてとCollectionをわかりやすくという記事を書きました!

今回はそのCollectionの操作について、基本的な部分を8つに分類してまとめてみました!
内容が長いので、何回かに分けて書くこととして、
第1回, transformationのものたちを書きます!⭐️

補足:
ドキュメントに沿ったような形でわかりやすくしてみたので、参考になれば嬉しいです!
この記事の全体の形としては、先にtableで書いて、それから基本形と例文を書いていく
形ですので少々長いですが、この記事を見ていただいた方は
興味の部分だけ見てもらえればと思います〜〜!

まずは以下に8つの分類を書いていき、以下項目でその内容を細かに書いていきます!
※メソッドはこれで全て,ではないです><

collections operations 概要 関数
transformation 既存のコレクションから新しいコレクションを構築 Map, Zip, Associate, Flatten, StringPresentation
それぞれのメソッドは詳細(今日の記事の下の内容)でまた別途記載
Filtering 元のコレクションを変更せずに特定の条件で要素をフィルタリングし、新しいコレクションを返す filter() (filterIndexed()) ,filterNot(), filterNotNull(), partition(),any,all,none
Plus / Minus コレクションに要素を追加または削除するもの plus(), minus()
Grouping コレクションの要素を特定の基準でグループ化するもの groupBy(), eachCount(),fold(), reduce(),aggregate()
Retrieving collection parts コレクションの一部を取得するもの slice(),Chunked ,Windowed ,take()(takeLast(),takeLastWhile(),takeWhile()),drop()(dropLast(),dropLastWhile(),dropWhile()),
Retrieving Single Elements コレクションから単一の要素を取得するもの By position ( elementAt(), elementAtOrElse(), elementAtOrNull()), by condition(first(), firstOrNull(), last() , lastOrNull(),find() ),Check Element Existence(contains(), isEmpty(), isNotEmpty())
Ordering コレクションの要素を並べ替えるもの Natural order(sorted(), sortedDescending()), Custom orders( sortedBy(), sortedByDescending(), sortedWith() ),Reverse order( reversed()),Random order( shuffled())
Aggreregate Operation コレクションの要素を集計するもの reduce(), fold(), count(), sum(), average(), max(), min() etc

\  では今回はCollection transformation,書いてくぞ〜! /

1. Collection transformation: 変換

The Kotlin standard library provides a set of extension functions for collection transformations.
These functions build new collections from existing ones based on the transformation rules provided.
提供された変換ルールに基づいて、既存のコレクションから新しいコレクションを構築

私はtableにまとめちゃうのが好きなのでまずはtableにします。笑
それからそれぞれの基本形と例のコードを書いていきます。

<Collection transformation>

関数 説明
Map map() (mapIndexed()) コレクション内の各要素に対して指定された変換を適用し、変換された要素からなる新しいコレクションを生成。
mapIndexed()はインデックスも使用して変換を適用。
mapNotNull() (mapIndexedNotNull()) 変換後にnullになる要素を除外して新しいコレクションを生成。
mapKeys() / mapValues() キーまたは値に対して変換を適用し、キーまたは値を新しいものに変更
Zip zip() 複数のコレクションをペアにまとめ、それぞれの対応する要素のペアを含む新しいリストを生成
Associate associateWith() 各要素に対して指定された値を関連付け、新しいマップを生成
MapのValueを作る
associateBy() 各要素に対して指定されたキーを関連付け、新しいマップを生成
MapのKeyを作る
associate() 各要素に対して指定されたキーと値のペアを関連付け、新しいマップを生成
MapのKeyもValueも作る
Flatten flatten() ネストされたコレクションからすべての要素を取り出し、1つの平坦なリストにする
flatMap() 各要素に対して指定された変換を適用し、それぞれの変換結果からなるリストを取得し、そのリストを平坦にした新しいリストを生成
String representation joinToString() 各要素を文字列に変換し、指定された区切り文字で区切った文字列を生成。接頭辞辞と接尾辞を指定することも可(separator, prefix, and postfix)
toString() 各要素を文字列に変換

Map

The mapping transformation creates a collection from the results of a function on the elements of another collection.
マッピング変換は、別のコレクションの要素に対する関数の結果からコレクションを作成する。

map()

  • コレクション内の各要素に対して指定された変換を適用し、変換された要素からなる
     新しいコレクションを生成するもの。
  • 指定したCollectionの各要素をラムダ式が返した値で置き換えた新しいCollectionを返す
    とも言える!

[基本型]

fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R>
// 日本語にしたら...
対象のコレクション.map(対象 -> 処理内容): 変換されたコレクション

ex.

val numbers = listOf(1, 2, 3, 4, 5)

// 各要素を2倍にするマッピング変換
val doubledNumbers = numbers.map { it * 2 }

println(doubledNumbers) // 出力: [2, 4, 6, 8, 10]

上記の例では、listOf関数を使用して整数のリストを作成,
そのリストの各要素に対してラムダ式 { it * 2 } を適用し,各要素を2倍にする変換を行っている。
その結果、doubledNumbersには元のリストの各要素が2倍されたリストが格納されることになる。

mapNotNull()

  • nullが入っているコレクションに対して、nullを許容し、変換結果がnullである要素を除外して
    処理を行うもの。
  • 与えられた変換関数(ラムダ式の中の処理)をコレクション内の各要素に適用し、
    null以外の結果からなる新しいcollection を生成する

[基本型]

fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R>

ex.

val numbers = listOf(1, 2, 3, 4, 5)
// 各要素を2倍にし、その結果がnullでない場合のみリストに追加
val doubledNonNullNumbers = numbers.mapNotNull{ 
    if (it % 2 == 0) it * 2 else null 
}

println(doubledNonNullNumbers) // 出力: [4, 8]

上記例は整数のリストを作成し、そのリストの各要素に対して条件付きのラムダ式 { if (it % 2 == 0) it * 2 else null } を適用し
各要素を2倍にして、結果がnullでない場合にその結果をリストに追加する。
null以外の結果からなる新しいリストを生成するので 、結果、
doubledNonNullNumbersには、
元のリストの偶数要素が2倍にされたリストが格納される!

Zip

Zipping transformation is building pairs from elements with the same positions in both collections. In the Kotlin standard library, this is done by the zip() extension function.
両方のコレクションで同じ位置を持つ要素からペアを構築するもの

zip()

  • 2つのコレクションからペアを作成し、
    それぞれに対応する要素のペアを含む新しいリストを生成するもの!

[基本形]

fun <T, R> Iterable<T>.zip(other: Iterable<R>): List<Pair<T, R>>

ex.

val numbers = listOf(1, 2, 3)
val letters = listOf("A", "B", "C")
val combined = numbers.zip(letters)

println(combined) // 出力: [(1, A), (2, B), (3, C)]

上記の例は、numberslettersという2つのリストを
zip()関数を使用してこれらのリストを結合し、
それぞれに対応する要素のペアを含む新しいリストを生成している

Associate

Association transformations allow building maps from the collection elements and certain values associated with them. In different association types, the elements can be either keys or values in the association map.
Association transformationsは、コレクションの要素とそれに関連する特定の値からマップを構築することを可能にする。

コレクションからMapを作りたいときに使用するぜ!!!!

個人的に学習し始めにここがよくわからなかったというか、よくこんがらがっていたので、
ちょっと他より詳しく書きます。
Associateは3つあって、これらは簡単にいうと以下のような感じ。

associateWith()

The basic association function associateWith() creates a Map in which the elements of the original collection are keys, and values are produced from them by the given transformation function. If two elements are equal, only the last one remains in the map.

  • 元のコレクションの要素をキーとするマップを作成し、
    そこから与えられた変換関数によって値を生成する。
    (2つの要素が等しい場合は、最後の1つだけがマップに残る。)
  • MapのValueを作る! -> Valueを作る処理をラムダの中に書こう!

[基本形]

fun <T, V> Iterable<T>.associateWith(transform: (T) -> V): Map<T, V>

ex.

val numbers = listOf("one", "two", "three")
val mapped = numbers.associateWith { it.length }

println(mapped) // 出力: {one=3, two=3, three=5}

上記の例では、numbersリストの各要素をその要素の長さにマップするためにassociateWith()関数を使用している。
mappedには、numbersリストの各要素がその要素の長さにマップされた結果がくる。

associateBy()

For building maps with collection elements as values, there is the function associateBy(). It takes a function that returns a key based on an element's value. If two elements' keys are equal, only the last one remains in the map.

  • 指定されたキー変換関数を各要素に適用し、その結果をキーとして、元の要素を値とする新しいマップを作成する。
  • MapのKeyを作る!-> マップのキーを作成するための処理をラムダの中に書こう!

<基本形>

fun <T, K> Iterable<T>.associateBy(keySelector: (T) -> K): Map<K, T>

ex.

val numbers = listOf("one", "two", "three", "four")

println(numbers.associateBy { it.first().uppercaseChar() }) // 出力 {O=one, T=three, F=four}
println(numbers.associateBy(keySelector = { it.first().uppercaseChar() }, valueTransform = { it.length }))

associateBy()は上記でも説明したように、"MapのKeyを作る"ので、その処理をラムダの中に書くと良い。
上記のコード例では、
一つ目の出力は、numbersリスト内の各文字列の先頭の文字を大文字に変換してキーとして使用する処理をラムダの中に書いている。
二つ目の出力では、キー変換関数とともに値変換関数も指定している。

associate()

Another way to build maps in which both keys and values are somehow produced from collection elements is the function associate(). It takes a lambda function that returns a Pair: the key and the value of the corresponding map entry.
<Note> that associate() produces short-living Pair objects which may affect the performance. Thus, associate() should be used when the performance isn't critical or it's more preferable than other options.
An example of the latter is when a key and the corresponding value are produced from an element together.

  • associate()はコレクションの要素からキーと値の両方を生成してマップを構築する
  • MapのKeyもValueも作る!

[基本型]

fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V>

ex.

val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")
println(names.associate { name -> parseFullName(name).let { it.lastName to it.firstName } })  
// 出力 {Adams=Alice, Brown=Brian, Campbell=Clara}

Flatten

If you operate nested collections, you may find the standard library functions that provide flat access to nested collection elements useful.
The first function is flatten(). You can call it on a collection of collections, for example, a List of Sets. The function returns a single List of all the elements of the nested collections.

ネストされたコレクションの要素を操作...

flatten()

The first function is flatten(). You can call it on a collection of collections, for example, a List of Sets. The function returns a single List of all the elements of the nested collections.

  • コレクションのコレクション(ex.セットのリスト)に対して呼び出すことが可能。
  • ネストされたコレクションのすべての要素からなる単一のリストを返す
  • 入れ子の Iterable を、単一の Iterable に詰め替え直す

<基本型>

fun <T> Iterable<Iterable<T>>.flatten(): List<T>

ex.

val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
// 出力 [1, 2, 3, 4, 5, 6, 1, 2]

上記例では、numberSetsSetのリストであり、
flatten()関数を使用することで、このリスト(numberSets)内のすべてのセットの要素が単一のリストにまとめた。

flatMap()

  • Collectionの各要素ごとにラムダ式(マッピング関数)がよばれる。
  • 各ラムダ式のコールで返された Iterable を1つの List にして返す

flatten()はネストされたコレクションをフラットにするだけだが、
flatMap()は各要素に対して変換や加工を行い、その結果をフラットなリストにする

[基本型]

fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R>

ex.

val containers = listOf(
    StringContainer(listOf("one", "two", "three")),
    StringContainer(listOf("four", "five", "six")),
    StringContainer(listOf("seven", "eight"))
)
println(containers.flatMap { it.values })
// 出力 [one, two, three, four, five, six, seven, eight]

というわけで次回は、Filteringから書きます!
よければまた見にきてください(^^)

自分のアウトプットのためにも書いてますが、
何か違うんじゃないか、とかあったら教えてください⭐️
そしてこの記事が誰かの助けにもなっていたら嬉しいです🎵

Discussion