根据元素的属性或其他条件缩小元素列表范围的好方法是什么?

2024-10-04 03:20:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我想按属性、类型或其他条件缩小列表中元素的范围。在

类似elements.only_type(Flower).get_nearest_to(player)的东西看起来比min(filter(lambda i: isinstance(i, Flower), elements), lambda i: i.pos.distance_to(player.pos)好看得多。在

从效率、干净的代码和简单性的角度来看,以下是一个好主意吗? 或者已经有一个好的方法,实现或者设计模式吗?在

class Selector(object):
    def __init__(self, selection):
        self.s3l3ct1on = selection

    def __getattr__(self, name):
        return type(self)(getattr(el, name) for el in self.s3l3ct1on)

    def __iter__(self):
        return iter(self.s3l3ct1on)

    def filter(self, function):
        return type(self)(filter(function, self.s3l3ct1on))

它的用法如下:(A只是一个具有两个属性的类:ab

^{pr2}$

Tags: tolambdaposselfreturn属性deftype
2条回答

为了简单起见,可以将类本身作为list的子类。在

class Elements(list):
   def only_type(self, t):
       return Elements(i for i in self if isinstance(i, t))

   def get_nearest(self, who):
       return min(self, key=lambda x: x.pos.distance_to(who.pos))

el = Elements([Flower(), Person(), Flower(), Something()])

el.only_type(Flower).get_nearest(player)

Selector相同

您提到的每种选择过程都可以用itertools迭代器来定义。下面的内容形式化了这一点,并且可以很容易地扩展到支持更多种类。使用它的语法似乎非常易读。在

虽然我没有做任何性能测试,但我希望结果是有竞争力的,因为几乎所有的开销都在构造函数方法中。唯一可能要快一点的方法是用等价的itertools迭代器函数替换它的用法,因此如果您希望进行大量此类处理,那么它可能是一个有效的方便工具。在

import itertools

class Selector(object):
    def __init__(self, iterable, **kwargs):
        if not kwargs:
            self.iterator = iterable
        elif len(kwargs) > 1:
            raise ValueError('only one selector type keyword allowed')
        else:
            selector, target = kwargs.items()[0]

            if selector == 'by_attr':
                self.iterator = itertools.imap(lambda obj: getattr(obj, target), iterable)
            elif selector == 'by_type':
                self.iterator = itertools.ifilter(lambda obj: isinstance(obj, target), 
                                                  iterable)
            elif selector == 'by_func':
                self.iterator = itertools.ifilter(target, iterable)
            else:
                raise ValueError('unknown selector type keyword')

    def __iter__(self):
        return self.iterator


if __name__ == '__main__':
    from selector import Selector

    class A(object):
        def __init__(self, a, b):
            self.a, self.b = a, b

    class Flower(object):
        def __init__(self, name):
            self.name = name

    sel = [A(3, 4), A(0, 9), A('test', 3), A(4,22), A(3, 9)]
    print list(Selector(sel, by_attr='a'))

    sel = [42, Flower('Buttercup'), [1,2,3,5,8], A(20, 13), Flower('Rose')]
    print list(Selector(sel, by_type=Flower))

    sel = [4, 9, 3, 22, 9]
    print list(Selector(sel, by_func=lambda i: i%2 == 0))

相关问题 更多 >