嵌套列表的dicts理解语法

时间:2014-07-28 16:20:57

标签: python dictionary list-comprehension

我有一个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'));        

2 个答案:

答案 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字段。