実際は「不可能という言葉はフランス的じゃない」みたいなニュアンスだったらしい

おまとめ三行

関数一つでは完結できないような機能をいくつか見ていきたい
もっと自作しなきゃいけないものが出てくるかも
どっちの言い方が一般的なんだろ?
前回はディクショナリでも使える関数をいくつか紹介しましたが、今日は関数一つでは完結できないような機能をいくつか見ていきたいと思います。



値を指定して取り除く

リストでは「remove()」を使うことでキーではなく値を指定して削除することができました。

array = ['a', 'b', 'c', 'd', 'e']
array.remove('a')

でもディクショナリにはこのremove的なものがたぶんないっぽいです(あったら教えていただきたい)

なので値を指定して削除する場合は、「items()」とループを使うなどの手間が必要そうです。

array = {'1':'a', '2':'b', '3':'c'}
for key, value in array.items():
  if value == 'a':
    array.pop(key)
    break

for文の説明については今回は省略。今度ループの話をやるんで、その時にまた。

一つ言えることは、ディクショナリをそのままfor文に使ってもキーしか取れないので、値も欲しいなら「items()」を使わなくてはならない。

あるいは「keys()」と「values()」を使うやり方も考えられますかね。

array = {'1':'a', '2':'b', '3':'c'}
keys = list(array.keys())
values = list(array.values())
index = values.index('b')
array.pop(keys[index])

「keys」と「values」がそれぞれ[1,2,3]、[a,b,c]というリストになるので、valuesの方から削除したい値のインデックスを取得し、keysの方の対応する値を取得して削除するやり方です。



値があるか調べる

リストの場合は「in」を使えば値があるかどうか判定できました。

array = ['a', 'b', 'c', 'd', 'e']
flg = 'a' in array

ディクショナリにもinを使うことはできるのですが、値ではなくキーが存在するかどうかを判定する動きになってしまいます。PHPの「isset()」や「array_key_exists()」みたいな感じ。だから値を指定しても、値と同じ値のキーがたまたま存在しない限りは何を指定してもFalseになる。

array = {'1':'a', '2':'b', '3':'c'}
flg = '1' in array #True
flg = 'a' in array #False

これも僕が調べた限りではディクショナリの値を判定できる関数がないので、自分でちょちょっとコードを書く必要があります。

array = {'1':'a', '2':'b', '3':'c'}
values = list(array.values())
flg = 'a' in values

やってることは値のリストを作って、それに対してin演算子を使っています。これなら有無を判定できる。



これはちょっとめんどいかもしれない。

「index()」を使えば値がリストのどこにあるかを調べることができます。

array = ['a', 'b', 'c', 'd', 'e']
i = array.index('a')

だったら先ほどと同じ要領で、「values()」でリスト化してindex()を使えばええやんって思いたくなるところですが、それだと不十分です。

ディクショナリは内部的に順番を保持してくれないので、values()を使って値のリストを作った場合、リストの中身が必ずしも順番通りになっているとは限りません。だからindex()を使うと望んでない値が返ってくることがある。

array = {'1':'a', '2':'b', '3':'c'}
values = list(array.values())
i = values.index('a')

この場合は0番目という結果が返ってきてほしいわけですが、valuesの中身は[‘a’,’b’,’c’]のこともあれば[‘b’,’a’,’c’]や[‘c’,’b’,’a’]になることもあるので、1や2が返ってくることもある。

そうならないためには以前にも何度か出てきた「OrderedDict」を使います。

import collections
array = collections.OrderedDict()
array['1'] = 'a'
array['2'] = 'b'
array['3'] = 'c'
values = list(array.values())
i = values.index('a')

これならリストが[‘a’,’b’,’c’]で固定されるので必ず0が返ってきます。



値からキーを取得

さっきの応用でPHPの「array_search()」と同じような動きを実装することもできます。キーの方もリスト化してindex()で照合すればいける。

import collections
array = collections.OrderedDict()
array['1'] = 'a'
array['2'] = 'b'
array['3'] = 'c'
keys = list(array.keys())
values = list(array.values())
i = values.index('a')
k = keys[i]

でもこれだったら値を取り除くところでやったfor文を使うやり方の方が楽かもですね。

array = {'1':'a', '2':'b', '3':'c'}
for key, value in array.items():
  if value == 'a':
    print(key)
    break

これなら順番の保持とか関係ないしね。

何にせよ、こんな感じの処理をメソッド化しておけば自作のarray_searchを用意することも可能です。






使い込んでいけばもっと自作しなきゃいけないものが出てくるかもしれないですが、今日はこんなところで。

僕の場合、PHPの「in_array()」はそこそこ使うことがあるので、もしpythonでがっつり開発をすることがあるのなら、この辺の処理はメソッドにしておきたいですね。

ところでディクショナリって言う方が一般的なのか、辞書って言う方が一般的なのか……どっちなんだろ?

ちなみに「ワガハイの辞書に関数はない」なんて言葉をナポレオンが残してないことはみなさんも承知だと思いますが、「ワガハイの辞書に不可能はない」ってのもちょっとニュアンスが違うらしい。実際は「不可能って言葉はフランス的じゃない」みたいな感じのことを言ったと言われています。

まあ、本当はどう言ったのかってのは確かめようがないですけどね。残念なことに過去へのタイムスリップは現時点では不可能ですから。フランス人にもできない。



その他のPythonを少し触ってみたの記事はこちら
前書きと索引的な