Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在类实例列表的列表属性中查找匹配项_Python_Generator_List Comprehension - Fatal编程技术网

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

Python 在类实例列表的列表属性中查找匹配项,python,generator,list-comprehension,Python,Generator,List Comprehension,我有一个类“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]) foo

我有一个类“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])
('gah', [])

print test('gah', [1, 2, 3])
会回来的

('def', [4, 5])
('gah', [])

这基本上是可行的,但看起来有点傻。我希望有一种方法可以使用列表理解或生成器使它更漂亮。我并不一定要将所有内容都展平到一个单行表达式中,因为我认为这几乎不可能读取,但我怀疑有更好的方法可以做到这一点。

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

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))

在线查看它的工作情况:

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

首先,我不考虑数据是列表,而是考虑一个集合。这将允许您使用

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, []
我意识到,如果你测试一个你没有的名字,你会得到一个键错误,所以我对它进行了适当的调整。

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

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

一种简单的改进方法:

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
,但tuple是一种更轻的数据结构

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

是否有多个具有相同名称的foo?@JochenRitzel unsed argument?你的意思是什么?你可以通过在我的查找中写入
if name:return name,my\u lookup[name].data.intersection(data)
——这将使
返回None
多余。实际上,当我更仔细地看问题时,OP指出了如果测试失败将返回什么,所以我继续把它写进了答案中。@g.d.d.c.我发现创建我的查字典并没有带来特别的好处。Simon Lundberg必须“循环查看实例列表以找到合适的实例”,但创建此词典时也要这样做。让my_lookup位于函数外部也会使my_lookup成为函数内部的自由标识符,这不是最好的做法:为了测试其他需要的数据,需要创建另一个my_lookup,然后逻辑是在函数内部引入它。但是,我的_查找的创建将与Simon代码中的非常相似。@agf“真的,这是正确的方法。”我不这么认为。我的回答说明了一切me@g.d.d.c我尝试使用字典中的
get()
方法来避免代码中有两行
return
,但没有成功。我发现这很复杂,而且最重要的是使用set会导致顺序丢失。谢谢大家。我已经重新构造了我的代码,现在工作得更好了。整个事情有点复杂,但目前这主要是因为我正在开发一款软件,它的Python集成基本上就是通过字符串发送命令的能力。非常感谢!