Upgrade to Pro — share decks privately, control downloads, hide ads and more …

よくつかっているIterableの自作extensionを紹介します

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for jsoizo jsoizo
April 07, 2023
100

 よくつかっているIterableの自作extensionを紹介します

Avatar for jsoizo

jsoizo

April 07, 2023
Tweet

More Decks by jsoizo

Transcript

  1. whoami • ໊લ: Jun Sekine @jsoizo • Blog: https://jsoizo.hatenablog.com/ •

    ॴଐ: גࣜձࣾίυϞϯ • Server Side Kotlin͸͡Ίͯ3ϲ݄΄ͲͰ͢ • લ͸ScalaΛ͔͍ͭͬͯ·ͨ͠, akka͕޷͖Ͱͨ͠ • KotlinͰ͸Arrow.kt͕޷͖ • Ϟφυͱ͔͸Α͘Θ͔ΒΜͰ͢
  2. partitionMap<F, S> = partition & map partition͸഑ྻͷ֤ཁૉʹରͯ͠predicateΛ࣮ߦ͠ ݁Ռ͕trueͳΒPairͷ fi rst,

    falseͳΒsecondʹͳΔ͕ɺ patitionMap͸ fi rst, secondͷ஋ΛͦΕͧΕmapͨ݁͠ՌΛฦ٫͢Δɻ fun <A, F, S> Iterable<A>.partitionMap( predicate: (A) -> Boolean, transformFirst: (A) -> F, transformSecond: (A) -> S ): Pair<List<F>, List<S>> = this.fold(Pair(emptyList(), emptyList())) { acc, it -> val (fList, sList) = acc if (predicate(it)) Pair(fList, sList.plus(transformSecond(it))) else Pair(fList.plus(transformFirst(it)), sList) }
  3. partitionMap<F, S> (Either൛) transformͷ݁ՌΛArrow.ktͷEitherͱ͢Δ͜ͱͰɺ ScalaͷpartitionMapͱಉ͡γάωνϟͱ͍ͯ͠Δɻ ม׵݁ՌͷEither͕Leftͷ৔߹͸ fi rst, Rightͷ৔߹͸secondʹ٧ΊΔɻ EitherͰόϦσʔγϣϯΛ࣮૷͍ͯ͠ΔࡍͷҰׅॲཧͳͲͰศར

    ※ ͓ͦΒ͘kotlin-resultͷResultΛར༻ͯ͠΋ಉ͜͡ͱΛ࣮ݱͰ͖Δ͸ͣ fun <A, F, S> Iterable<A>.partitionMap( transform: (A) -> Either<F, S> ): Pair<List<F>, List<S>> = this.fold(Pair(emptyList(), emptyList())) { acc, it -> val (fList, sList) = acc transform(it).fold({ Pair(fList.plus(it), sList) }, { Pair(fList, sList.plus(it)) })
  4. partitionMap<F, S> (Either൛) csvಡΈࠐΈ౳ʹΑΓෳ਺ͷΦϒδΣΫτΛҰׅͰੜ੒͠ɺ ͢΂ͯόϦσʔγϣϯ͕௨ͬͨ৔߹ͷΈอଘ͞ΕΔɺͱ͍͏ྫ data class PersonValidateError: DomainError data

    class Person private constructor(val name: String, val age: Int) { companion object { fun of(name: String, age: Int): Either<PersonValidateError, Person> } } data class Row(val col1: String, val col2: Int) val rows = listOf(Row("Alice", 20), Row("Bob", -2), Row("", 35)) val (errors, validatedPersons) = rows.partitionMap({ Person.of(it.col1, it.col2) }) // errors: List<PersonValidateError> validatedPersons: List<Person> if (errors.isNotEmpty()) savePersons(validatedPersons)
  5. partitionMap<F, S> (Either൛ ͜΅Ε࿩) Arrow.ktʹPull Requestग़ͯ͠࠷ऴతʹ͜͏ͳͬͨ👏1.2.0ʹೖΓ·͢🎉 https://github.com/arrow-kt/arrow/pull/3004 fun <A, F,

    S> Iterable<A>.separateEither( transform: (A) -> Either<F, S> ): Pair<List<F>, List<S>> { val left = mutableListOf<F>() val right = mutableListOf<S>() for (item in this) { when (val either = transform(item)) { is Either.Left -> left.add(either.value) is Either.Right -> right.add(either.value) } } return Pair(left, right) }
  6. collect<B> = fi lter & map<B> ഑ྻͷ֤ཁૉʹରͯ͠conditionΛ࣮ߦ͠ɺ ݁Ռ͕trueͷ৔߹͸ͦͷཁૉΛtransformʹ͔͚ͨ݁ՌΛฦ٫͢Δɻ ※ Scalaͷcollect͸Ҿ਺͕PartialFunction[A,

    B]ͳͷͰ΋ͬͱෳࡶͳ৔߹෼͚͕Մ (PartialFunction ≒ ࢦఆͨ͠৚݅ԼͰͷΈ஋Λฦ͢ύλʔϯϚον) Ώ͑ʹยखམͪײ͕൱Ίͣɺਖ਼௚mapNotNullͰे෼ͱײ͡Δ͜ͱ͕ଟ͍ fun <A, B> Iterable<A>.collect(condition: (A) -> Boolean, transform: (A) -> B): List<B> = this.mapNotNull { if (condition(it)) transform(it) else null }
  7. collect<B> = fi lter & map<B> ςετͷ఺਺Ϧετͷத͔Βӳޠͷ఺਺͚ͩΛநग़͠੔ܗ͢Δྫ val scores =

    listOf( Triple("Alice", "Math", 90), Triple("Alice", "English", 78), Triple("Bob", "Math", 50), Triple("Bob", "English", 80), ) val englishScoresPrettyPrinted = scores.collect( { it.second == "English" }, // condition: (T) -> Boolean { "${it.first} - ${it.third}఺" } // transform: (T) -> A ) // Alice - 78఺ // Bob - 80఺
  8. collectFirstOrNull<B> = collect<B> & fi rstOrNull<B> ഑ྻͷ֤ཁૉʹରͯ͠conditionΛ࣮ߦ͠ɺ ࠷ॳʹ݁Ռ͕trueʹͳͬͨཁૉΛtransformʹ͔͚ͯฦ٫͢Δɻ condition͕trueʹͳΔཁૉ͕ͳ͍৔߹͸nullΛฦ٫͢Δɻ fi

    nd{ condition(it) }?.let { transform(it) } ͱಉ༷ͱ΋͍͑Δɻ ͜Ε·ͨಉ༷ʹPartialFunction͕ͳ͍Ώ͑ fi rstNotNullOfOrNullͰࣄ଍ΓΔ͜ͱଟ͠… fun <A, B> Iterable<A>.collectFirstOrNull( condition: (A) -> Boolean, transform: (A) -> B ): B? = this.firstNotNullOfOrNull { if (condition(it)) transform(it) else null }
  9. collectFirstOrNull<B> = collect<B> & fi rstOrNull<B> ςετͷ఺਺Ϧετͷத͔Βӳޠͷ఺਺͚ͩΛ1͚ͭͩநग़͠੔ܗ͢Δྫ val scores =

    listOf( Triple("Alice", "Math", 90), Triple("Alice", "English", 78), Triple("Bob", "Math", 50), Triple("Bob", "English", 80), ) val emptyScores = emptyList<Triple<String, String, Int>> val englishScoresPrettyPrinted = scores.collectFirst( { it.second == "English" }, // condition: (T) -> Boolean { "${it.first} - ${it.third}఺" } // transform: (T) -> A ) // Alice - 78఺ // ಉ͡ॲཧΛemptyScoresʹରͯ͠ߦ͏ͱnull͕ฦ٫͞ΕΔ
  10. groupMapReduce<K, V> groupBy<K, V>(keyTransform: (A) -> K, valueTransform: (A) ->

    V) ͷvalueΛ͞Βʹreduceͨ͠΋ͷɻ σʔλͷूܭͳͲͰ༻͍Δ͜ͱ͕ଟ͍ɻ(ఆٛͯ͋͠Δ͚ͩͰࠓͷͱ͜Ζະ࢖༻) fun <A, K, V> Iterable<A>.groupMapReduce( keyTransform: (A) -> K, valueTransform: (A) -> V, valueReduce: (V, V) -> V ): Map<K, V> = this.fold(mutableMapOf()) { acc, it -> val key = keyTransform(it) val current = acc.get(key) val value = valueTransform(it) acc[key] = current?.let { valueReduce(it, value) } ?: value acc }
  11. groupMapReduce<K, V> class ScoresRecord (val name: String, val kamoku: String,

    val season: String, val value: Int) val scores = listOf( ScoresRecord("Alice", "਺ֶ", "21೥্ظ", 100), ScoresRecord("Alice", "ӳޠ", "21೥্ظ", 100), ScoresRecord("Bob", "਺ֶ", "21೥্ظ", 100), ScoresRecord("Bob", "ӳޠ", "21೥্ظ", 100), … ) value class PositiveInt(val value: Int) { fun plus(other: PositiveInt) = PositiveInt(this.value + other.value) } val scoresPerNameKamoku = scores.groupMapReduce( { Pair(it.name, it.kamoku) }, // keyTransform: (T) -> K { PositiveInt(it.value) }, // valueTransform: (T) -> V { a1, a2 -> a1.plus(a2) } // valueReduce: (V, V) -> (V) )