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 3 years have passed since last update.

言語処理100本ノック 2020を解く(01. 「パタトクカシーー」)

Last updated at Posted at 2020-05-19

はじめに

巷で流行っている自然言語100本ノックにPythonで挑戦してみます。
解き方はいろいろあると思うので、いろいろな解き方を示したいと思います。
全ての解き方を網羅することは当然ながらできません。
「こんな解き方があるよ」や「ここ間違ってるよ」という点があれば、ぜひコメントでお教えいただければと思います。

言語処理100本ノック 2020とは

言語処理100本ノック 2020は、東北大学の乾・鈴木研究室のプログラミング基礎研勉強会で使われている教材です。
詳しくは、言語処理100本ノックについてを参照して下さい。

Qiitaの記事へのリンク

1問目 2問目 3問目 4問目 5問目 6問目 7問目 8問目 9問目 10問目
第1章 00 01 02 03 04 05 06 07 08 09
第2章 10 11 12 13 14 15 16 17 18 19
第3章 20 21 22 23 24 25 26 27 28 29
第4章 30 31 32 33 34 35 36 37 38 39
第5章 40 41 42 43 44 45 46 47 48 49
第6章 50 51 52 53 54 55 56 57 58 59
第7章 60 61 62 63 64 65 66 67 68 69
第8章 70 71 72 73 74 75 76 77 78 79
第9章 80 81 82 83 84 85 86 87 88 89
第10章 90 91 92 93 94 95 96 97 98 99

01. 「パタトクカシーー」

問題

01. 「パタトクカシーー」の問題は、下記の内容です。

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

解答

問題を読むと、パタトクカシーーの1,3,5,7文字目なので、答えはパトカーです。
以下に示すどの解答でも、最後の式を評価するとパトカーと返ってきます。

シンプル

素直に文字列の末尾に追加していく方法があります。
enumerate(s)は、n=len(s)として(0,s[0]),...,(n-1,s[n-1])を走査するためのイテレータを返します。

# シンプル
s = "パタトクカシーー"

result = ""
for n,c in enumerate(s):
    if n%2==0:
        result += c
result #=> 'パトカー'

関数型的

関数型由来のmapfilterを使って書くこともできます。
この例ではあまりメリットを感じられませんね…。

# 関数型的
s = "パタトクカシーー"

"".join(
    map(
        lambda x:x[1],
        filter(
            lambda x:x[0]%2==0,
            enumerate(s)
        )
    )
) #=> 'パトカー'

ラムダ式で定義した関数に名前を付けたほうが若干ましでしょうか。

# 関数型的
s = "パタトクカシーー"

second_elem = lambda x:x[1]
is_first_elem_even = lambda x:x[0]%2==0

"".join(map(
        second_elem,
        filter(
            is_first_elem_even,
            enumerate(s)
        )
    )
) #=> 'パトカー'

名前を付けすぎるとやりすぎに感じますね。

# 関数型的
s = "パタトクカシーー"

first_elem = lambda x:x[0]
second_elem = lambda x:x[1]
is_first_elem_even = lambda x:first_elem(x)%2==0

"".join(map(
        second_elem,
        filter(
            is_first_elem_even,
            enumerate(s)
        )
    )
) #=> 'パトカー'

これくらいの関数は準備されていてほしいですね。
なお、ラムダ式による関数定義は、下記の通常の関数定義と一緒です。

def first_elem(x):
    return x[0]

def second_elem(x):
    return x[1]

def is_first_elem_even(x):
    return first_elem(x)%2==0

おとなしく変数に入れたほうがいいかもしれません。
filtermapが返してくるのはイテレータ(ジェネレータ)なので、変数に入れるたびにリストが生成されたりはしません。
JavaScriptみたいに、コールバックが後ろ側のほうがよかった気がしてなりません。

# 関数型的
s = "パタトクカシーー"

first_elem = lambda x:x[0]
second_elem = lambda x:x[1]
is_first_elem_even = lambda x:first_elem(x)%2==0

filtered = filter(is_first_elem_even, enumerate(s))
mapped = map(second_elem, filtered)
"".join(mapped) #=> 'パトカー'

内包表記

mapfilterにこだわらずに、内包表記で書いたほうが簡単です。
[x for x in l]と書くとリスト内包表記ですし、(x for x in l)と書くとジェネレータ内包表記です。
f((x for x in l))は、f(x for x in l)とかっこを一つ減らして書くことができます。
複数の変数に値を同時に代入すれば、xで受け取ってx[0]x[1]で取り出すよりもわかりやすくなります。

# 内包表記
s = "パタトクカシーー"

"".join(c for n,c in enumerate(s) if n%2==0) #=> 'パトカー'

Pythonic

Python的であることを Pythonic といいますが、このコードが一番Pythonicでしょうか。
リストや文字列に対して、s[start:end:step]でアクセスする方法をスライスと呼びます。
step2を指定すると1こ飛ばしになります。

# Pythonic
s = "パタトクカシーー"

s[::2] #=> 'パトカー'

その他の解答

インデックスで回す

enumerateなんて使わずに、自分でインデックスを用意して回す方法もあります。

# 自力で回す
s = "パタトクカシーー"

result = ""
n = 0
for c in s:
    if n%2==0:
        result += c
    n += 1
result #=> 'パトカー'

リストに追加して後で結合する

言語処理100本ノック 2020を解く(01. 文字列の逆順)と同じようにリストに追加して後で結合することもできます。

# シンプル
s = "パタトクカシーー"

l = []
for n, c in enumerate(s):
    if n%2==0:
        l.append(c)
"".join(l) #=> 'パトカー'

振り返り

「文字列を結合する」のと「リストに追加する」のとどっちがいいか悩むことがあります。
文字ではなく一般のオブジェクトのリスト扱うなら必然的にリストに追加することになりますが、今回のようにゴールが文字列の生成ならどちらでもいいんじゃないでしょうか。
サイズが大きくなって遅くなってきたら立ち止まって考えましょう。

# シンプル
s = "パタトクカシーー"

result = ""
for n,c in enumerate(s):
    if n%2==0:
        result += c
result #=> 'パトカー'
# シンプル
s = "パタトクカシーー"

l = []
for n, c in enumerate(s):
    if n%2==0:
        l.append(c)
"".join(l) #=> 'パトカー'
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?