Skip to content

Instantly share code, notes, and snippets.

@ryohji
Last active January 6, 2022 01:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryohji/c4ea6fe1c4958eb75fa794aaa43cb669 to your computer and use it in GitHub Desktop.
Save ryohji/c4ea6fe1c4958eb75fa794aaa43cb669 to your computer and use it in GitHub Desktop.
ループをつかわない辞書構築

たとえば『ゼロから作るDeep Learning (2)』に以下のコード片がある。(P.66)

def preprocess(text):
  text = text.lower()
  text = text.replace('.', ' .')
  words = text.split(' ')

  word_to_id = {}
  id_to_word = {}
  for word in words:
    if word not in word_to_id:
      new_id = len(word_to_id)
      word_to_id[word] = new_id
      id_to_word[new_id] = word

  corpus = np.array([word_to_id[w] for w in words])

  return corpus, word_to_id, id_to_word

ぼくだったら、これはこう書きたい:

def preprocess(text: str) -> Tuple[np.array, Dict[str, int], Dict[int, str]]:
  words = text.lower().replace('.', ' .').split(' ')
  id_to_word = {k: v for k, v in enumerate(set(words))}
  word_to_id = {v: k for k, v in id_to_word.items()}
  corpus = np.array([word_to_id[w] for w in words])
  return corpus, word_to_id, id_to_word

id_to_worddict(enumerate(set(words))) で計算してもよい。

とにかく「for 文を書いたら負け」とくらいおもっている。

words の単語の重複を set で取りのぞき、その要素それぞれに enumerate でインデックスをつける。
これを辞書にして id_to_word という名前をつける。そして id_to_word のキーと値をひっくり返した辞書を word_to_id とする。
──単語それぞれにユニークな番号を振る。そして単語から番号へと、番号から単語への逆引きができるようにする。


あるいはたまたまだけれど、新人教育の一環でみた INI ファイルの亜種を相手にするコードの解答のひとつがこんな具合:

def line_to_dict(lines: List[str]) -> Dict[str, str]:
  reading = False
  result = {}
  for line in lines:
    if line == '[PARAM START]':
      reading = True
    elif line == '[PARAM END]':
      reading = False
    elif reading:
      words = line.split('=')
      result[words[0]] = words[1]
  return result

いくつか暗黙の仮定があることはごめんなさいなんだけれど、これもぼくだったらこう書く(こう書くことを勧めたい):

def line_to_dict(lines: List[str]) -> Dict[str, str]:
  beg, end = (lines.index(s) for s in ('[PARAM START]', '[PARAM END]'))
  return dict(_mk_kv_pair(l) for l in lines[beg + 1:end] if '=' in l)

def _mk_kv_pair(line: str) -> Tuple[str, str]:
  i = line.index('=')
  return (line[:i], line[i + 1:])

for 文を書いたら負けだし、なんだったら「if の条件分岐だって書いたら負け」という戦をしている。 (dict コンストラクターでのジェネレーター内包表記で、フィルターとしてつかってしまった。負けた。負け戦だ……)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment