Three words (Library 2.0) - 3つ連続した単語を探せ
どんな問題?
Three words
http://www.checkio.org/mission/three-words/
スペースで区切られた複数の単語や数字が含まれている文字列がある。
単語は文字(a-zA-Z)のみを含むものとする。
文字列に、3つ連続した単語が含まれているかをチェックせよ。
なんか問題文の意味が把握できなくて苦労したが、よーするに、単語が3つ続いてればOKということだろう。
「数字 単語 単語 単語 数字」は、True
「単語 単語 数字 単語 単語」は、False
例題:
checkio("Hello World hello") == True checkio("He is 123 man") == False checkio("1 2 3 4") == False checkio("bla bla bla bla") == True checkio("Hi") == False
どうやって解く?
単語か数字かの判定は、ヒントにあるようにisalpha()で判断すればいいとして。
連続して3つ、という部分をどうするか。
まず、引数の文字列、例えば "He is 123 man" を [True, True, False, True] というboolのリストに変換して、そこに連続3つのTrueが出てくるかどうかを調べることにする。
文字列なら部分文字列が含まれているかどうかは、 in を使えばいい。リストをいったん文字列に変換して調べることにする。
def checkio(words): tokens = words.split(' ') s = ''.join(['1' if t.isalpha() else '0' for t in tokens] return '111' in s
文字列 "He is 123 man" を、boolのリスト [True, True, False, True] に変換する。
TrueとFalseを、'1'と'0'に置き換えて文字列 '1101' にする。
この中に '111' が含まれているかをチェック。
1行で書くとこうなる。
def checkio(words): return '111' in ''.join(['1' if t.isalpha() else '0' for t in words.split(' ')])
テストはクリア&ひとまず公開。
別解を考える
いったん文字列に変換する、というのはやはり正攻法ではない気がする。
もっとストレートに、リストの中から部分リストを検索するにはどうしたらいいかな?
シーケンス(seq)に、部分シーケンス(sub_seq)が含まれているかどうかを調べる関数を作ってみた。
def contains(seq, sub_seq): # Return True if the sequence contains the sub-sequence return any(sub_seq == seq[i:i + len(sub_seq)] for i in range(len(seq) - len(sub_seq) + 1)) contains([1, 2, 3, 4, 5], [3, 4]) # True contains([1, 2, 3, 4, 5], [4, 3]) # False
リストに限らず、タプルや文字列、ジェネレータでも使える。(seqとsub_seqは同じタイプでなくてはならない。)
全体はこうなった。
def contains(seq, sub_seq): return any(sub_seq == seq[i:i + len(sub_seq)] for i in range(len(seq) - len(sub_seq) + 1)) def checkio(words): seq = [t.isalpha() for t in words.split(' ')] sub_seq = [True] * 3 return contains(seq, sub_seq)
せっかくなので、こっちも公開しておこう。