在类实例列表的列表属性中查找匹配项

2024-04-27 00:24:07 发布

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

我有一个类“Foo”,它有一个名称(字符串)和一组数据(整数列表)。我需要能够找到'测试'任何字符串/列表组合对Foo的名单,找到任何匹配。像这样:

class Foo:
    def __init__(self, name, data):
        self.name = str(name)
        self.data = list(data)


foo1 = Foo('abc', [1, 2, 3])
foo2 = Foo('def', [4, 5, 6])
foo3 = Foo('ghi', [7, 8, 9])

my_list = [foo1, foo2, foo3]

def test(name, data):
    results = []
    for foo in my_list:
        if foo.name == name:
            for number in data:
                if number in foo.data:
                    results.append(number)
    return name, results

print test('def', [2, 3, 4, 5])

会回来的

('def', [4, 5])

而。。。你知道吗

print test('gah', [1, 2, 3])

会回来的

('gah', [])

这基本上是可行的,但看起来有点傻。我希望有一种方法可以使用列表理解或生成器使它更漂亮。我并不一定要把所有的东西都扁平化为一行表达式,因为我认为这几乎是不可能的,但我怀疑有更好的方法来做到这一点。你知道吗


Tags: 字符串nameintestselfnumber列表data
3条回答

这基本上是可行的,但看起来有点傻。
不傻,只是没有经验。你知道吗

我希望有一种方法可以使用列表理解生成器使它更漂亮。(…)我怀疑有更好的方法。
当然,你的直觉很好。你知道吗

一种简单的改进方法:

class Foo:
    dicfoos = {}
    def __init__(self, name, data):
        self.name = str(name)
        self.data = list(data)
        self.__class__.dicfoos.setdefault(self.name,[]).append(self) 

foo1 = Foo('abc', [1, 2, 3])
foo2 = Foo('def', [4, 5, 6])
foo3 = Foo('ghi', [7, 8, 9])
foo4 = Foo('def', [10, 11, 12])

def test(klass,the_name, wanted_data):
    return (the_name,
            tuple( x for foo in klass.dicfoos.get(the_name,())
                   for x in foo.data if x in wanted_data ) )

print test(Foo,'zzz', [2, 3, 4, 5, 11])
print test(Foo,'def', [2, 3, 4, 5, 11])
print test(Foo,'abc', [2, 3, 4, 5, 11])

结果

('zzz', ())
('def', (4, 5, 11))
('abc', (2, 3))

更复杂一点的方法:

class Foo:
    dicfoos = {}
    def __init__(self, name, data):
        self.name = str(name)
        self.data = list(data)
        self.__class__.dicfoos.setdefault(self.name,[]).append(self)
    def sift(self,daataa):
        for n in self.data:
            if n in daataa:  yield n

foo1 = Foo('abc', [1, 2, 3])
foo2 = Foo('def', [4, 5, 6])
foo3 = Foo('ghi', [7, 8, 9])
foo4 = Foo('def', [10, 11, 12])


def test(klass,the_name,wanted_data):
    return (the_name,
            tuple( x for foo in klass.dicfoos.get(the_name,())
                   for x in foo.sift(wanted_data) ) )

print test(Foo,'zzz', [2, 3, 4, 5, 11])
print test(Foo,'def', [2, 3, 4, 5, 11])
print test(Foo,'abc', [2, 3, 4, 5, 11])

如果确实需要,可以将名称tuple替换为list,但元组是一种较轻的数据结构

编辑

考虑到注释中的一个注释g.d.d.c,我用字典dicfoos替换了列表lifoos:后者避免了在需要精确名称的实例时进行查找,具有该精确名称的itel给出了此类实例的列表

似乎可以重新构造代码中的许多内容,使其工作得更好。你知道吗

首先,与其让数据成为一个列表,不如考虑一个集合。这将允许您使用data.intersection(otherdata)来获得重叠。你知道吗

下一步,不是Foo实例的列表,而是由它们的名称键入的字典?这将允许您通过测试名称对其进行索引,而不必在实例列表上循环查找合适的实例。你知道吗

class Foo:
    def __init__(self, name, data):
        self.name = str(name)
        self.data = set(data)


foo1 = Foo('abc', [1, 2, 3])
foo2 = Foo('def', [4, 5, 6])
foo3 = Foo('ghi', [7, 8, 9])

my_lookup = dict((f.name, f) for f in [foo1, foo2, foo3])

def test(name, data):
    if name in my_lookup:
        return name, my_lookup[name].data.intersection(data)
    return name, []

我意识到,如果你测试一个你没有的名字,你会得到一个键错误,所以我调整了它来处理这个问题。你知道吗

可以使用集合而不是列表:

from itertools import chain

def test(name, data):
    data = frozenset(data)
    return name, list(chain.from_iterable(data & set(foo.data)
                                          for foo in my_list
                                          if foo.name == name))

在线查看:ideone

相关问题 更多 >