1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Kotlin】バーグ・ザッカーマーク

Last updated at Posted at 2022-06-21

元ネタ

シャッフルする文字をあらかじめ抜き出しておいて、残りの文字のテンプレートに埋め込む方法

fun main() {
    "マクザカバグ"
        .toList()
        .shuffled()
        .let { "${it[0]}ー${it[1]}・${it[2]}ッ${it[3]}ー${it[4]}ー${it[5]}" }
        .also { println(it) }
}

半手動という感じ。

偶数インデックスの文字だけシャッフルする方法

fun main() {
    "マーク・ザッカーバーグ"
        .map { "$it" } // CharSequence を List<String> に変換する。
        .let { it + "" } // 要素数が偶数になるように、List<String> の末尾に空文字列を加える。
        .withIndex()
        .partition { (index, _) -> index % 2 == 0 } // 偶数インデックスの要素と奇数インデックスの要素に分ける。
        .let { (evens, odds) -> evens.shuffled() zip odds }
        .flatMap { it.toList() }
        .joinToString("") { it.value }
        .also { println(it) }
}

要素数を偶数にしないと zip で最後の1つが無視されてしまうため、
最初に各文字(Char)を文字列(String)にして最後に空文字を追加している。
(奇数の場合だけ追加、とすべきだろうが、今回は省略した。)

withIndex するのはいいが、IndexedValue になった値から元の値を取り出す(it.value )のが後の方になっているのでわかりにくい(partition の直後にやってもいいが、2つの List に対して行わなければならないので冗長になる)。
partition 関数にも filterIndexed 関数のような、predicate にインデックスがついてくるものが欲しい。

partition ではなく filterIndexed を使うと次のようになる。

fun main() {
    "マーク・ザッカーバーグ"
        .map { "$it" }
        .let { it + "" }
        .let {
            it.filterIndexed { index, c -> index % 2 == 0 } to
                    it.filterIndexed { index, c -> index % 2 != 0 }
        }
        .let { (even, odd) -> even.shuffled() zip odd }
        .flatMap { it.toList() }
        .joinToString("")
        .also { println(it) }
}

filterIndexed がほぼ同じ引数で2回出てくるのが冗長だが、partition 版より読みやすいか。

文字列のスワップを使う方法

fun main() {
    val original = "マーク・ザッカーバーグ"
    val replacingIndex = original.indices.step(2).toList() // -> [0, 2, 4, 6, 8, 10]
    buildString {
        append(original)

        (replacingIndex zip replacingIndex.shuffled()).forEach { (from, to) ->
            val fromChar = this[from]
            val toChar = this[to]
            this[from] = toChar
            this[to] = fromChar
        }
    }.also { println(it) }
}

ワンライナーにはできないのでこんな感じで。

String に、指定されたインデックスの文字を入れ替える関数さえあれば、一応ワンライナー(1文)にできる。

fun main() {
    "マーク・ザッカーバーグ".let {
        it to it.indices.step(2).toList()
    }.let { (original, replacingIndexes) ->
        (replacingIndexes zip replacingIndexes.shuffled())
            .fold(original) { str, (from, to) ->
                str.swapped(from, to)
            }
    }.also { println(it) }
}

/** 指定されたインデックスの文字を入れ替える。 */
fun String.swapped(atA: Int, atB: Int): String =
    StringBuilder(this).also {
        val charA = it[atA]
        val charB = it[atB]
        it[atA] = charB
        it[atB] = charA
    }.toString()

/続くかも

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?