Home About
Kotlin

ポケモン名のリストから最も出現頻度の高いポケモンをみつける(Kotlin編)

決定木のプログラミングをしているときに必要になった関数。 これを備忘録としてメモしておきます。

とりあえず完成したコード

main.kt

data class PokemonAndCount(val name: String, val count: Int)

typealias Condition = (String) -> Boolean

val countif: (List<String>, Condition)-> Int = { list, f->
    list.filter { f(it) }.size
}

val toPokemonAndCountList: (List<String>)->List<PokemonAndCount> = { list->
    list.distinct().map { pokemonName-> 
        val count =  countif(list, { it==pokemonName })
        PokemonAndCount(pokemonName, count)
    }
}

val toPokemonNameWithMaxCount: (List<String>)->String = { list->
    // ここで PokemonAndCount インスタンスの count 値を基準にソート(昇順)、ソート後、リストの最後のそれの name 値を返す.
    toPokemonAndCountList(list).sortedWith( compareBy { it.count } ).last().name
}

fun main(){
    val pokemonList0 = "Pikachu,Charmander,Squirtle,Pikachu,Metapod".split(",")
    println( toPokemonNameWithMaxCount(pokemonList0) ) // → Pickachu

    val pokemonList1 = "Squirtle,Pikachu,Charmander,Squirtle,Pikachu,Metapod,Squirtle".split(",")
    println( toPokemonNameWithMaxCount(pokemonList1) ) // → Squirtle
}

例によって以下の Makefile でコンパイルと実行を行う。

run: main.jar
	java -jar main.jar

main.jar: main.kt
	kotlinc main.kt -include-runtime -d main.jar

改良を試みる

ポケモン名が String として表現されている部分を Pokemon 型(クラス)に置き換えてみた。

data class Pokemon(val name: String)
data class PokemonAndCount(val pokemon: Pokemon, val count: Int)

typealias Condition = (Pokemon) -> Boolean

val countif: (List<Pokemon>, Condition)-> Int = { list, f->
    list.filter { f(it) }.size
}

val toPokemonAndCountList: (List<Pokemon>)->List<PokemonAndCount> = { list->
    list.distinct().map { pokemon-> 
        val count =  countif(list, { it.name==pokemon.name })
        PokemonAndCount(pokemon, count)
    }
}

val toPokemonWithMaxCount: (List<Pokemon>)->Pokemon = { list->
    toPokemonAndCountList(list).sortedWith( compareBy { it.count } ).last().pokemon
}

fun main(){
    val pokemonList0 = "Pikachu,Charmander,Squirtle,Pikachu,Metapod".split(",").map{name-> Pokemon(name)}
    println( toPokemonWithMaxCount(pokemonList0) )

    val pokemonList1 = "Squirtle,Pikachu,Charmander,Squirtle,Pikachu,Metapod,Squirtle".split(",").map{name-> Pokemon(name)}
    println( toPokemonWithMaxCount(pokemonList1) )
}

Pokemon データクラスを追加した上で、 ポケモン名を String として表現した部分を Pokemon に置き換えただけ。 (toPokemonWithMaxCount 関数名は変更した。)

コードはわかりやすくなったが、抽象度は下がった。 抽象度を下げたからコードがわかりやすくなった、というべきか。