我有一个类'Foo',它有一个名字(字符串)和一组数据(一个整数列表)。我需要能够在Foo列表中找到'test'任何字符串/列表组合,以找到任何匹配项。像这样:
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', [])
这基本上有效,但看起来有点傻。我希望有一种方法可以使用列表理解或生成器来使它更漂亮。我没有必要将所有内容压缩成一个单行表达式,因为我预计这几乎是不可能阅读的,但我怀疑有更好的方法可以做到这一点。
答案 0 :(得分:4)
您似乎可以重新构建代码中的许多内容,以使其更好地工作。
首先,我不是将数据作为列表,而是考虑一个集合。这样您就可以使用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, []
我意识到,如果你测试了一个你没有的名字,你会得到一个KeyError,所以我调整它以适当地处理它。
答案 1 :(得分:1)
您可以使用集而不是列表:
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
答案 2 :(得分:0)
这基本上有效,但看起来很傻。
不傻,只是未经实验。
我希望有一种方法可以使用列表理解或生成器来使它更漂亮。 (...)我怀疑这是更好的方式。
当然,你的直觉很好。
一种改进的简单方法:
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
,但元组是更轻的数据结构
在评论中考虑了 gddc 的评论后,我将字典 lifoos 替换为字典 dicfoos :后者避免了查找需要精确名称的实例,具有此精确名称的itel给出了此类实例的列表