比較関数を追加可能なcomparator

夕方にちょっと話にでてきたので想像で実装してみた。

class ExtensibleComparator(object):
    def __init__(self):
        self.ops = []
        
    def __call__(self,  x, y):
        for op in self.ops:
            n = op(x, y)
            if n == -1:
                return -1
            elif n == 1:
                return 1
        return 0
            
    def add(self, op):
        self.ops.append(op)

def compare_fuctory(key_fn):
    def _compare(x, y):
        xx,  yy = key_fn(x), key_fn(y)
        if xx == yy:
            return 0
        return 1 if xx > yy else -1
    return _compare

使い方

こんな風に使う

from collections import namedtuple

fact = namedtuple("F", "cost benefit")

xs = [fact(4, 4), fact(5, 10),  fact(10, 20), fact(5, 8), fact(10, 10)]

ec = ExtensibleComparator()
# costの順で並べる
ec.add(compare_fuctory(lambda x : x.cost))
print sorted(xs, ec)
# costが同じだったら、benefitの順で並べる
ec.add(compare_fuctory(lambda x : x.benefit))
print sorted(xs, ec)

###
print "--------"
ec2 = ExtensibleComparator()
# benefit/costの値で並べる
ec2.add(compare_fuctory(lambda x : x.benefit / x.cost))
print sorted(xs, ec2)
# 比率が同じだったら、benefitの大きいものから順に並べる。
ec2.add(compare_fuctory(lambda x : -x.benefit))
print sorted(xs, ec2)

結果

使った結果

[F(cost=4, benefit=4), F(cost=5, benefit=10), F(cost=5, benefit=8), F(cost=10, benefit=20), F(cost=10, benefit=10)]
[F(cost=4, benefit=4), F(cost=5, benefit=8), F(cost=5, benefit=10), F(cost=10, benefit=10), F(cost=10, benefit=20)]
--------
[F(cost=4, benefit=4), F(cost=5, benefit=8), F(cost=10, benefit=10), F(cost=5, benefit=10), F(cost=10, benefit=20)]
[F(cost=10, benefit=10), F(cost=5, benefit=8), F(cost=4, benefit=4), F(cost=10, benefit=20), F(cost=5, benefit=10)]

たぶんこんな感じのものだと予想してる。