Python 100本ノックを始めました。 9本目

09. Typoglycemia

問題

  • スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ. ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文 (例えば"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .") を与え,その実行結果を確認せよ.

イメージした処理の流れ

①文章を単語ごとにリスト化
②並べ替える対象の文字を抽出し、ランダム文字列一覧を作成
③文字数でフィルター
④③で抽出した文字から、並べ替える文字数分ランダムに選択する
⑤④で使用した文字を、ランダム文字列一覧から削除
⑥「先頭文字 + ④で作成したランダム文字列 +末尾」を作成する
⑦リスト内の並べ替え前の文字列と、並べ替え後の文字列を入れ替える
⑧③-⑦をリスト内の全単語でループ処理
⑨文章として表示

作成したコード

import random

def str_random(n):
    a = "" #並べ替え用文字列を格納
    b = [] #単語へ置き換える文字を格納

    #文章をリストに変換(①)
    str_list = n.split(" ")

    #先頭と末尾以外の並べ替える文字の候補(a)を作成(②)
    for x in range(len(str_list)):
        if len(str_list[x]) > 3:
            a += str_list[x][1:-1]

    for x in range(len(str_list)): #⑧
        c = "" #先頭と末尾以外の文字列を入れ替えた単語を格納
        if len(str_list[x]) > 3: #③
            #置き換える文字(b)を候補(a)から抽出(④)
            b = random.sample(a, k=len(str_list[x])-2)
            for y in b:
                #置き換える文字(b)をリストから文字列に変換
                c += y
                #使用した並べ替え候補をリスト(a)から削除(⑤)
                a = a.replace(y, "", 1)
            #並べ替えた単語を作成(⑥,⑦)
            str_list[x] = str_list[x][0]  + c + str_list[x][-1]
    #入れ替えた単語を表示する(⑨)
    print(" ".join(str_list))

str_random("I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."))

実行結果

I cmemdeot bilniue ttht I cewod auoeaeny ueislvr'nd wnat I was rlhndag : the pnolcathal puenr of the hlaun madd .

感想

最初、処理④の時にrandom.choicesを使用していて同じ文字列が重複して選ばれていました。( ’ が複数出てきていて気が付きました。)

抽出する際に重複させない場合は、random.samplesを使用することを認識しました。

しかし、次の単語を作成する前に使用した文字列を削除する必要性に気が付いたので以下のような処理に変更しました。

for y in b:
    #置き換える文字(b)をリストから文字列に変換
    c += y
    #使用した並べ替え候補をリスト(a)から削除(⑤)
    a = a.replace(y, "", 1)

結果、一文字ずつ処理をしているのでrandom.samplesに変更した意味はなくなりました。。

ただ、この処理はなんだか野暮ったい感じに見えます。
もっと良い処理方法はないものか。。