我有一个dicts列表,其中一个值是另一个dicts列表。我正在尝试按照第二层dicts列表中的值进行过滤(在下面的示例中为color
)。第一种方法是正确的方法吗?或者是否有更简单的一两个班轮?我的背景是在MATLAB中,所以我习惯于对结构数组进行逻辑索引。
次要问题:除了嵌套的词典列表之外,还有更好的方法来表示这些数据吗?
testrecord = [{'testnum':1,'testdata':[{'datanum':1,'color':'green'},{'datanum':2,'color':'blue'},{'datanum':3,'color':'green'}]},
{'testnum':2,'testdata':[{'datanum':1,'color':'yellow'},{'datanum':2,'color':'orange'},{'datanum':3,'color':'red'}]},
{'testnum':3,'testdata':[{'datanum':1,'color':'red'},{'datanum':2,'color':'yellow'},{'datanum':3,'color':'green'}]}]
#Method 1:
datamatch1 = []
for tr in range(len(testrecord)):
for td in range(len(testrecord[tr]['testdata'])):
if testrecord[tr]['testdata'][td]['color']=='green':
datamatch1.append(testrecord[tr]['testdata'][td])
#Method 2 (has an unnecessary extra list layer):
datamatch2 = []
for tr in range(len(testrecord)):
datamatch2.append([td for td in testrecord[tr]['testdata'] if td['color']=='green'])
%MATLAB alternative:
datamatch = [testrecord.testdata];
datamatch = temp(strcmp({temp.color},'green'));
答案 0 :(得分:3)
这可以通过一个相当简单的列表理解来完成:
>>> [t for testrec in testrecord for t in testrec['testdata'] if t.get('color') == 'green']
[{'color': 'green', 'datanum': 1}, {'color': 'green', 'datanum': 3}, {'color': 'green', 'datanum': 3}]
为了更好地理解创建这样的列表组合,将其分解为嵌套的for循环:
for testrec in testrecord:
for t in testrec['testdata']:
if t.get('color') == 'green':
#include
t
然后你摆脱终点冒号,并将返回的值移到前面
t
for testrec in testrrecord
for t in testrec['testdata']
if t.get('color') == 'green')
然后将它包装在list comprehension的方括号
中[t for testrec in testrecord for t in restrec['testdata'] if t.get('color') == 'green']
答案 1 :(得分:0)
几乎可以肯定,有一种更好的方法来构建数据。在这种情况下看到“testnum”和“datanum”只是顺序索引,相同数量的信息可以存储在一个简单的列表列表中:
testlist = [['green','blue','green'],
['yellow','orange','red'],
['red','yellow','green']]
使用enumerate()
(此处转换为列表以打印内容)可以轻松获取包含索引的元组:
>>> list(enumerate(testlist))
[(0, ['green', 'blue', 'green']), (1, ['yellow', 'orange', 'red']), (2, ['red', 'yellow', 'green'])]
>>> [list(enumerate(x)) for x in testlist]
[[(0, 'green'), (1, 'blue'), (2, 'green')], [(0, 'yellow'), (1, 'orange'), (2, 'red')], [(0, 'red'), (1, 'yellow'), (2, 'green')]]
没有必要迭代索引,你的例子都使用range(len(testrecord))
进行迭代。在命名结构很重要的情况下,使用类来保存记录也是有意义的;至少slots他们可以比字典更好地扩展。
当谈到使用嵌套的理解时,我发现拆分它们很方便,因为你可以在括号内添加任何你想要的新行:
>>> matches = [(recno,datano,data)
... for recno,record in enumerate(testlist)
... for datano,data in enumerate(record)
... if data=='green']
>>> matches
[(0, 0, 'green'), (0, 2, 'green'), (2, 2, 'green')]
在这种情况下,我将索引存储为原始数据结构,保留了datanum
字段。