Help us understand the problem. What is going on with this article?

joinToStringがとても便利だったので今更紹介する

概要

今回は単発&短めです

SQLのqueryやAPIリクエスト時のURLパラメータなど、とあるデータから配列からカンマ区切りで要素をStringにしたものを使ったり、そこにprefixをつけたりだとかするときに皆さんはどうするでしょうか
(自分はyoutubeAPIにカンマ区切りで複数のパラメータを渡す際にどうしようかと思っていました)

StringBuilderを作ってappendしたり、配列をそのまま文字列に変換してreplaceしたり色々やり方はありそうですね

ただ今回は、標準実装されているjoinToStringがとても便利だなと思ったので今更ですが紹介&解説させていただきたいと思います

解説

元コードはこちらです

_Collections.kt
/**
 * Creates a string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied.
 * 
 * If the collection could be huge, you can specify a non-negative value of [limit], in which case only the first [limit]
 * elements will be appended, followed by the [truncated] string (which defaults to "...").
 * 
 * @sample samples.collections.Collections.Transformations.joinToString
 */
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
    return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}

collection, sequenceに対して使うことができます
※上記のコードはIterableのものです

引数がかなり豊富で取り回しがききます

  • separator -> 要素をそのままつなげるわけではなく、それぞれにseparatorを指定できます

    • | でも - でも , でも。空白であればそのままです
  • prefix -> 文字通り連結したものの先頭に加えたいものを指定できます

  • postfix -> 最後に加えたいものを指定できます

  • limit -> 連結する際、何個の要素まで使うか指定できます

    • defaultは-1つまりlimitをかけないということですが、これが2だった場合は連結する要素は2つまでということになります
  • truncated -> limitと合わせて使うものになります。limitによって配列の要素が全て使われず省略されてしまう場合に、ここで指定した文字列を追加することができます

    • 例えば ... としておくと文字列の最後に...が付与されて省略された形を表現できます
    • ただし、上述したpostfixが設定されている場合はそれが最後にくることに注意してください
  • transform -> 関数から値の変換ができます mapのようなものですね

実装

試しにかんたんな例を実装してみます

fun main() {
    val records = listOf(Record("Hoge", "Huga", 20000),
                         Record("A", "B", 2500),
                         Record("B", "C", 1200)
                         )
    val result = records.joinToString(limit=2, truncated="...", prefix="---*** ", postfix=" ***---", separator = ", ", transform = {
            record -> "${record.from} -> ${record.to} (${record.price})"
        })
    println(result)
}

data class Record(val from: String, val to: String, val price: Int)

誰が誰あてにどれほどのお金を振り込んだかを表すレコードとでも思ってください
実際にこのような形で実行すると

---*** Hoge -> Huga (20000), A -> B (2500), ... ***---

とてもきれいな出力が得られました 便利です

競技プログラミングでも使えそうですね

上記コードはこちらのKotlin Playgroundでお試しできます

ref

sudo5in5k
しがないAndroiderやってまうs
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away