PHPしか知らない僕がPythonを少し触ってみたよ 〜ディクショナリをいじくり回す〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
僕はB型です

この記事を三行にまとめると

今日はディクショナリ(辞書)をいじってみましょう
ほら、さっそくitems()の出番があったでしょ?
三兆ってすごくね? 数字で書いたら3000000000000だぜ
前回はリストをいろいろといじってみましたが、今日はディクショナリ(辞書)をいじってみましょう。PHPで言うところの連想配列を操作する感じですね。

PHPの何らかの関数に相当するものもあれば、PHPならこの関数で一発だけどPythonだとちょこっとコードを書き足さないと同様の動きを実現できないってものもあります。今回は関数のあるものを見てみましょう。コードの書き足しが必要なのは次回に回します。



要素を追加する

では基本の要素の追加から。

//PHP
$array[0] = 'a';

#Python
array = {}
array[0] = 'a'

Pythonのリストでは「append()」という関数を使って要素を追加しましたが、辞書の場合はPHPと同じようなやり方で要素を追加できます。ただしPHPみたくいきなり要素を追加するとエラーになってしまいます。Pythonの場合、初期値を設定するなら良いのですが、そうじゃない場合は最初に変数の型を指定しておかないといけない。もちろんディクショナリ型以外を定義してしまうと、要素を追加しようと思ったときにエラーになります。

#初期値あり(エラーにならない)
array = {0:'a', 1:'b'}
array[2] = 'c'

#初期値なし(エラー)
array[0] = 'a'

#型が違う(エラー)
array = ''; #str型
array[0] = 'a'

添え字は数字以外もOKですが、値を入力するときにPHPみたく省略することはできません。

//PHP
$array[0] = 'a'; //OK
$array['a'] = 1; //OK
$array[] = 'b'; //OK

#Python
array[0] = 'a'; #OK
array['a'] = 1; #OK
array[] = 'b'; #NG



キーだけを取り出す

辞書からキーだけを取り出してリストを生成する方法です。PHPで言う「array_keys()」に相当するものですね。

//PHP
$array = array('1' => 'a', '2' => 'b', '3' => 'c');
$keys = array_keys($array);

#Python
array = {'1':'a', '2':'b', '3':'c'}
keys = array.keys()

これで「1,2,3」のリストが取得できます。リストと言っても正確には「dict_keys」とかいうオブジェクトが返ってくるので、リストにしか使えないような操作をしたい場合は、型をリスト型に直す必要があります。

array = {'1':'a', '2':'b', '3':'c'}

#エラーになる
keys = array.keys()
keys.pop(0)

#エラーにならない
keys = list(array.keys())
keys.pop(0)

それから、前に配列の基礎のところでもちょろっと言いましたが、辞書は内部的に順番の保持を行ってません。なので上記のコードも必ずしも順番通りに[1, 2, 3]となるとは限りません。順番を保持したい場合は「OrderedDict」を使って辞書を作成する必要があります。OrderedDictの使い方については配列の基礎の記事を見てくれぃ。



値だけ取り出す

今度は値だけ取り出す場合。PHPだと「array_values()」ですね。

//PHP
$array = array('1' => 'a', '2' => 'b', '3' => 'c');
$values = array_values($array);

#Python
array = {'1':'a', '2':'b', '3':'c'}
values = array.values()

これもkeysと一緒で、返ってくるのは「dict_values」というオブジェクトなので、リスト操作する場合はリスト型に直す必要がある。順番が保持されないのも同様です。順番通りに値を取りたいなら「OrderedDict」が必要になります。



キーと値を両方取り出す

次はキーと値をまとめて取り出す方法です。PHPにはこれに相当するものはないと思うんで、Pythonのコードだけ紹介。

array = {'1':'a', '2':'b', '3':'c'}
items = array.items()

返ってくるオブジェクトは「dict_items」です。やっぱり順番は保持されない。「キーと値を両方取るならarrayをそのまま使えばええやん。順番が入れ替わるだけ無駄じゃね?」と思いたくもなりますが、意外と出番が多いような気がするので、知っておいて損はないはず。



任意の要素を取り除く

キーを指定して要素を取り除くやり方はリストと一緒で「pop()」を使います。

//PHP
$array = array('1' => 'a', '2' => 'b', '3' => 'c');
unset($array('2'));

#Python
array = {'1':'a', '2':'b', '3':'c'}
array.pop('2')

これでキーが「2」の要素を取り除けます。

注意点があるとすればPythonの方は型を意識する必要があるってことですね。上記のようにコーテーションで囲った場合、キーの数字はint型ではなくstr型になるので、int型でキーを指定しても要素は取り除けません。

//PHP(「'2' => 'b'」が取り除かれる)
$array = array('1' => 'a', '2' => 'b', '3' => 'c');
unset($array(2));

#Python(そんなキーはないというエラーが出る)
array = {'1':'a', '2':'b', '3':'c'}
array.pop(2)



「del」も使えます。

array = {'1':'a', '2':'b', '3':'c'}
del array['2']

コンマ区切りでまとめて複数の要素を削除することも可。

array = {'1':'a', '2':'b', '3':'c'}
del array['1'], array['2']

PHPとunset()もコンマ区切りで複数の要素を削除できるので、感覚的には一緒ですね。



先頭の要素を取り除く

リストの場合はPHPの「array_shift()」に相当するものがありませんでした。厳密に言えばディクショナリにも「array_shift()」と全く同じ動きをするのものはないみたいなのですが、同じ動きになるかもしれないものならある。

//PHP
$array = array('1' => 'a', '2' => 'b', '3' => 'c');
array_shift($array);

#Python
array = {'1':'a', '2':'b', '3':'c'}
array.popitem()

「popitem()」は要素を一つだけ取り除く関数です。どの要素が取り除かれるかは決まってないっぽいです。だから先頭の要素が取り除かれることもあるし、それ以外の要素が取り除かれることもある。確実に先頭の要素を取り除きたい時に使うのはやめた方が良さそうですね。

ちなみにOrderedDictで作成したディクショナリにpopitem()を使うと、最後の要素が取り除かれるようです。僕がやった限りではそうだった。もし違う動きもすることがあるって場合はご一報くだせえ。



辞書を連結

二つの辞書を連結するやり方。PHPの「array_merge()」ですね。

//PHP
$array1 = array('1' => 'a');
$array2 = array('2' => 'b', '3' => 'c');
$array = array_merge($array1, $array2);

#Python
a = {'1':'a'}
b = {'2':'b', '3':'c'}
a.update(b)

リストの場合は「+」でも連結することができましたが、辞書に「+」は使えません。連結する場合は上記のように「update()」で。



ソート

リストをソートするときは「array.sort()」や「sorted(array)」を使いますが、ディクショナリも「sorted(array)」でソートできます。「array.sort()」は使えない。

array = {'1':'a', '2':'b', '3':'c'}
array = sorted(array) #昇順
array = sorted(array, reverse = True) #降順

リストの場合は値でソートされますが、ディクショナリの場合はキーでのソートになります。だからこれはPHPで言うところの「ksort()」「krsort()」に該当する動きになりますね。

ただしこれには注意点があって、実際にやってみれば分かるんですが、arrayを出力するとキーのリストが返ってきちゃいます。

array = {'1':'a', '2':'b', '3':'c'}
array = sorted(array)
print(array)

#出力結果
['1', '2', '3']

つまりこのやり方では値が取れない。キーと値の両方が欲しい場合は「sorted」に「array.items()」を渡してやる必要があります。ほら、さっそくitems()の出番があったでしょ? 知ってて良かった公文式。

array = {'1':'a', '2':'b', '3':'c'}
array = sorted(array.items(), reverse = True)
print(array)

#出力結果
[('3', 'c'), ('2', 'b'), ('1', 'a')]

これならソートしつつキーと値の両方を取得できます。ただしキーだけのときと同じで、これも返ってくるのはリストになります。だから「array[‘3’]」で「c」が取れるわけではなく「array[0]」で「(‘3’, ‘c’)」を取得するようになります。

array = {'1':'a', '2':'b', '3':'c'}
array = sorted(array.items(), reverse = True)

#「('3', 'c')」を取得
array[0]

#「3」を取得
array[0][0]

#「c」を取得
array[0][1]

「(‘3’, ‘c’)」はタプル型と呼ばれる型なのですが、扱い方はリストと似ています。だから[‘3’, ‘c’]というリストから「3」や「c」を取得するような感覚でオーケーです。



値でソートする

キーでソートする方法は分かりました。じゃあ値でソートするにはどうしたら良いかというと「無名関数(lambda)」ってやつを使います。

array = {'1':'a', '2':'b', '3':'c'}
array = sorted(array.items(), key = lambda x : x[1]) #昇順
array = sorted(array.items(), key = lambda x : x[1], reverse = True) #降順

「lambda x : x[1]」ってのが無名関数の部分。無名関数の詳細についてはまた今度やりたいと思いますが、今回の場合はざっくり言えば以下のような動きと同じです。

def sample(x):
  return x[1]

key = sample(('1', 'a'))

「def」ってのはPHPで言う「function」です。ここでは「sample()」という関数にタプル型の要素を渡して、1番目の値を返してもらっています。この場合は「a」が返ってきます。これを各要素に対して行うことで、値でのソートが可能になるって感じです。






探せばまだまだいろいろあると思いますが、よく使うのはこの辺りじゃないでしょうか。僕の場合、PHPでも「array_keys()」や「array_merge()」はちょくちょく使うので、似たような機能をPythonで実装するならやはりその辺を使うことがあるのかなって思います。あとはソートもかな。

それにしてもPythonはずいぶんと型が多い気がしますね……血液型なんて目じゃないな。でもPHPだとあまり意識しないってだけで、実際はどの言語もこれくらい細かく型が分かれてるものなんですかね。

そういや馬の血液型の種類は三兆あるんだって。三兆ってすごくね? 数字で書いたら3000000000000だぜ。世界中の馬を合わせても三兆もいないよね?



その他のPythonを少し触ってみたの記事はこちら
前書きと索引的な
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください