Python 在类实例列表的列表属性中查找匹配项
我有一个类“Foo”,它有一个名称(字符串)和一组数据(整数列表)。我需要能够找到“测试”任何字符串/列表的组合,对照Foo的列表,找到任何匹配项。像这样: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
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集成基本上就是通过字符串发送命令的能力。非常感谢!