リストのソート
"文字+数字"形式のリストを数字でソートしたい。
ネットで検索しても全然見つからなかったので、うまいやり方ではないかもしれませんが、
書いてみました。
回路図の部品表や、IC(特にBGA)のPIN番号などがこういった形式になっています。
文字列はFPGAのPIN番号リストを抜粋しました。
1次元の場合
単純なソート
list1 = ["A1","A2","A3","A10","A11","A12","A13","A20","A21","A22","A23","A30","A31","A32"]
list1.sort()
print(list1)
結果:
桁がそろわない。
['A1', 'A10', 'A11', 'A12', 'A13', 'A20', 'A2', 'A21', 'A22', 'A23', 'A3', 'A30', 'A31', 'A32']
文字列の数字部分でソート
intでソートすれば番号順に並ぶので、いったん数値だけ取り出してソートした後、元のリストを取り出す。
import re
list1 = ["A1","A2","A3","A10","A11","A12","A13","A20","A21","A22","A23","A30","A31","A32"]
sort_list = [(re.search("[0-9]+", x).group(), x) for x in list1] # ["数字", "元の文字列"]
sort_list.sort(key=lambda x:int(x[0])) # 数字をintでソート
print([x[1] for x in sort_list]) # 元の文字列だけ取り出す
結果:
['A1', 'A2', 'A3', 'A10', 'A11', 'A12', 'A13', 'A20', 'A21', 'A22', 'A23', 'A30', 'A31', 'A32']
もう少し複雑な場合
例えば、大規模なBGAの場合、A1~Yxxのあと、AA1から番号が続きます。
★★コメントに記載していただいた方法がシンプルです。考え方は以下になります。★★
# ここは見やすくするため書き方適当です。
list1 =
["A1","A2","A3","A10","A11","A12","A20","A21","A22","AA1","AA2","AB1","AB2",
"B1","B2","B3","B10","B11","B12","BB1","BB2","BB3","C1","C2"]
import re
# [ "文字", "数字", "元の文字列" ]
sort_list = [( re.search("[a-zA-Z]+", x).group(), re.search("[0-9]+", x).group(), x) for x in list1]
sort_list.sort(key=lambda x:(x[0],int(x[1]))) # 文字 > 数字 の優先度でソート
print([x[2] for x in sort_list]) # 元の文字列だけ取り出す
結果:
文字でソートしただけでは、A,B,C,...,AA,AB,...の順にはならない。
['A1', 'A2', 'A3', 'A10', 'A11', 'A12', 'A20', 'A21', 'A22',
'AA1', 'AA2', 'AB1', 'AB2',
'B1', 'B2', 'B3', 'B10',
'B11', 'B12', 'BB1', 'BB2', 'BB3', 'C1', 'C2']
文字数も考慮
import re
# [ "文字", "数字", "元の文字列" ]
sort_list = [( re.search("[a-zA-Z]+", x).group(), re.search("[0-9]+", x).group(), x) for x in list1]
sort_list.sort(key=lambda x:(len(x[0]),x[0],int(x[1]))) # 文字数 > 文字 > 数字 の優先度でソート
print([x[2] for x in sort_list]) # 元の文字列だけ取り出す
結果:
['A1', 'A2', 'A3', 'A10', 'A11', 'A12', 'A20', 'A21', 'A22',
'B1', 'B2', 'B3', 'B10', 'B11', 'B12', 'C1', 'C2',
'AA1', 'AA2', 'AB1', 'AB2', 'BB1', 'BB2', 'BB3']
2次元の場合
考え方は1次元と同じ。
3次元以上も同様にできるはず。
リスト例:
# ここは見やすくするため書き方適当です。
# [ "PIN番号", "機能名" ]
list2 =
[['A1', 'GND'], ['A2', 'GND'], ['A10', 'IO_L2N_AD14N_94'], ['A11', 'IO_L2P_AD14P_94'],
['A20', 'IO_L1P_AD15P_91'], ['A21', 'IO_L22N_T3U_N7_DBC_AD0N_72'],
['AA1', 'GND'], ['AA2', 'GND'],
['AB1', 'MGTHRXN1_229'], ['AB2', 'MGTHRXP1_229'],
['B1', 'MGTHRXN1_234'], ['B2', 'MGTHRXP1_234'],
['BA1', 'GND'], ['BA2', 'GND'],
['BB1', 'GND'], ['BB2', 'GND'],
['C1', 'GND'], ['C2', 'GND'],
['D1', 'MGTHRXN3_233'], ['D2', 'MGTHRXP3_233']]
単純なソート
list2.sort(key=lambda x:x[0])
print(list2)
結果:
[['A1', 'GND'], ['A10', 'IO_L2N_AD14N_94'], ['A11', 'IO_L2P_AD14P_94'],
['A2', 'GND'], ['A20', 'IO_L1P_AD15P_91'], ['A21', 'IO_L22N_T3U_N7_DBC_AD0N_72'],
['AA1', 'GND'], ['AA2', 'GND'], ['AB1', 'MGTHRXN1_229'], ['AB2', 'MGTHRXP1_229'],
['B1', 'MGTHRXN1_234'], ['B2', 'MGTHRXP1_234'],
['BA1', 'GND'], ['BA2', 'GND'], ['BB1', 'GND'], ['BB2', 'GND'],
['C1', 'GND'], ['C2', 'GND'], ['D1', 'MGTHRXN3_233'], ['D2', 'MGTHRXP3_233']]
文字数、文字、数値でソート
import re
list3 = []
for i in range(len(list2)):
num = re.search("[0-9]+", list2[i][0]).group() # 数字だけ取り出す
text = re.search("[a-zA-Z]+", list2[i][0]).group() # 文字だけ取り出す
list3.append([len(text), text, num, list2[i][0], list2[i][1]]) # ["文字数", "文字", "数字", "元の文字列"]
list3.sort(key=lambda x:(int(x[0]),x[1],int(x[2]))) # 文字数 > 文字 > 数字 の優先度でソート
# 元のリストを取り出す
sort_list = []
for i in range(len(list3)):
sort_list.append([ list3[i][3], list3[i][4] ])
print(sort_list)
結果:
[['A1', 'GND'], ['A2', 'GND'], ['A10', 'IO_L2N_AD14N_94'], ['A11', 'IO_L2P_AD14P_94'],
['A20', 'IO_L1P_AD15P_91'], ['A21', 'IO_L22N_T3U_N7_DBC_AD0N_72'],
['B1', 'MGTHRXN1_234'], ['B2', 'MGTHRXP1_234'],
['C1', 'GND'], ['C2', 'GND'], ['D1', 'MGTHRXN3_233'], ['D2', 'MGTHRXP3_233'],
['AA1', 'GND'], ['AA2', 'GND'], ['AB1', 'MGTHRXN1_229'], ['AB2', 'MGTHRXP1_229'],
['BA1', 'GND'], ['BA2', 'GND'], ['BB1', 'GND'], ['BB2', 'GND']]