Skip to content

2023 07 02

【Python】比較関数を使ってソートする

functoolsのcmp_to_keyを使うことで比較関数を使ってソートできる。 単純なソートはkeyにlambda式を使えばよいが、さらに複雑なソートを行う場合に利用できる。 例: abc308 C(有効数字による誤差防止のため2値の値が必要) https://docs.python.org/ja/3.7/library/functools.html#functools.cmp_to_key

from functools import cmp_to_key

# A[(a, b, c),...]
A = [
    (5, 10, 1),
    (100, 34, 2),
    (1, 3, 3),
    (57, 33, 4),
    (100, 100, 5),
    (78,66, 6),
    (10, 10, 7),
]

# Aを下記の通りにソートしたい
# 1. a / (a + b)の降順
# 2. 1で値が同じ場合はcの昇順
def cmp(a, b) -> int:
    """
    a, bを比較し、aがより小さい(リストの後ろ側)の場合は負数
    より大きい場合は正数
    同値の場合は0を返す
    """
    # 有効数字による誤差を避けるため乗算で比較する
    # a1 * (a2 + b2) 対 a2 * (a1 + b2)
    v1 = a[0] * b[1]
    v2 = a[1] * b[0]
    if v1 == v2:
        if a[2] == b[2]:
            return 0
        elif a[2] < b[2]:
            return -1
        else:
            return 1
    else:
        if v1 < v2:
            return 1
        else:
            return -1

A.sort(key=cmp_to_key(cmp))

# [(100, 34, 2), (57, 33, 4), (78, 66, 6), (100, 100, 5), (10, 10, 7), (5, 10, 1), (1, 3, 3)]
print(A) 

【Python】割り算結果の大小比較

\(a_1,a_2,b_1,b_2\)を整数としたとき、\(\frac{a_1}{a_1+b_1}, \frac{a_2}{a_2+b_2}\)の大小比較をする場合、単純に比較するだけでは浮動小数点の精度不足で正しく比較できない。 正しく比較する方法は以下の通り。 1. Pythonでは多倍長整数が利用できるため。十分な桁数で比較するために例えば\(10**100\)などを掛けてから比較する。 2. Decimalを利用する。デフォルトでは28?桁のため、桁数を増やしたい場合は下記のように桁数を指定する。 (ただしPyPyを利用する場合かなり実行速度が遅いため注意)

from decimal import getcontext
getcontext().prec = 100 # 桁数