Pythonで2つのリストを関係を保持したままソートする
Pythonで2つの配列を関係を保持したままソートする方法
例えば以下のような2つのリストをソートする場合を考えます
list1 = [1, 3, 5, 2, 7, 9, 4]
list2 = ['one', 'three', 'five', 'two', 'seven', 'nine', 'four']
list1
を昇順でソートする場合にはsorted()
を使用します
>>> list1 = [1, 3, 5, 2, 7, 9, 4]
>>> sorted(list1)
[1, 2, 3, 4, 5, 7, 9]
ここでlist2
もlist1
のソートに合わせて
>>> list2 = ['one', 'two', 'three', 'four', 'five', 'seven', 'nine']
のようにソートする場合は少し手間がかかりそうですが、zip()
関数を使用すると一行で記述できます
>>> list1 = [1, 3, 5, 2, 7, 9, 4]
>>> list2 = ['one', 'three', 'five', 'two', 'seven', 'nine', 'four']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 2, 3, 4, 5, 7, 9)
>>> list2
('one', 'two', 'three', 'four', 'five', 'seven', 'nine')
何がおこったのかを詳しく見ていきます
zip()
関数は複数のイテレータを受け取り、要素毎にタプルでグループ化したリスト (イテレータ)を生成してくれます。上記コードの内側のzip()
は以下のようなリストを作成します
>>> list(zip(list1, list2))
[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'), (7, 'seven'), (9, 'nine')]
このリストをsorted()
関数でソートします
>>> sorted(zip(list1, list2))
[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five'), (7, 'seven'), (9, 'nine')]
sort()
はデフォルトでは最初の要素をキーとしてソートするため、整数の昇順にソートされます。仮に2番目のリストの要素でソートしたい場合は以下のようにkey
引数で指定します
>>> sorted(zip(list1, list2), key=lambda x: x[1])
[(5, 'five'), (4, 'four'), (9, 'nine'), (1, 'one'), (7, 'seven'), (3, 'three'), (2, 'two')]
上記のようにソートされた2つの要素からなるリストを再度外側のzip()
に渡して、最初の要素 (list1
の要素)と2番目の要素(list2
の要素)をグループ化したリストに分解します
>>> list(zip(*sorted(zip(list1, list2))))
[(1, 2, 3, 4, 5, 7, 9), ('one', 'two', 'three', 'four', 'five', 'seven', 'nine')]
この時zip()
関数に渡す際に上記のように*
でアンパックする必要があります。アンパックを忘れると[(1, 'one'), (2, 'two'), ...]
のような1つのリストを渡すことになるため、zip()
も1つのリストを含んだ1つのタプルを返してくれるだけになります。
最後に、この方法は3つ以上のリストをソートする場合も同様です
>>> list1 = [1, 3, 5, 2, 7, 9, 4]
>>> list2 = ['one', 'three', 'five', 'two', 'seven', 'nine', 'four']
>>> list3 = ['ichi', 'san', 'go', 'ni', 'nana', 'kyu', 'yon']
>>> list(zip(*(zip(list1, list2, list3))))
[(1, 3, 5, 2, 7, 9, 4),
('one', 'three', 'five', 'two', 'seven', 'nine', 'four'),
('ichi', 'san', 'go', 'ni', 'nana', 'kyu', 'yon')]
最近のコメント