继续外循环几次,当退出内循环时(Python)
Continue outer-loop several times, when exit inner-loop (Python)
我有一个内部循环和一个外部循环(数据库中的记录)。外循环(json)根据几个字段(例如:begin/end => 0 : 0.5 >>> ID 114 到 159)创建一个过滤器。
Table :
ID begin end status FK1_field FK2_field FK3_field FK4_field FK5_field report_id
114 0 0.5 1 NULL 13 8 142 44 1
115 0 0.5 1 NULL 13 8 61 45 1
158 0 0.5 1 NULL 13 8 142 45 1
159 0 0.5 1 NULL 13 8 61 44 1
116 0.5 1.5 1 NULL 13 8 142 45 1
117 0.5 1.5 1 NULL 13 8 131 45 1
118 1.5 2.5 1 NULL 13 8 142 45 1
结果在内部循环上循环(例如:4 records/lines (*))。
但是,当我退出内循环时,我必须在外循环上循环 4 次 (*) 以获得 ID 116(和过滤器 begin/end)=> 0.5 : 1.5.
的确,我可以只遍历内部循环并用 'if' 测试相同的几次。但我认为过滤更优雅。
现在,我认为退出内部循环时循环是愚蠢的。
代码:
highways = tools_cronjob.getAPI(API_URL + action, headers)
for highway in highways:
print('>>>>> Highway : %s ' % highway['name'])
# all the prpk, same values like the table
prpk_by_highway = tools_cronjob.getAPI(API_URL + actions_api['prpk_by_highway'] + "%s" % (highway['id']), headers)
# get all prpk by highway
for prpk in prpk_by_highway:
filtered_by_begin_end = [pr_pk for pr_pk in prpk_by_highway if pr_pk['begin'] == prpk['begin']]
# each couple of prpk 'begin' and 'end'
for filter_prpk in filtered_prpk_by_begin_end:
# some stuff
print (filter_prpk)
# when I exit, for eg, I must continue looping (prpk in prpk_by_highway) starting the couple begin/end : 0.5 : 1.5
所以第一个循环是 4 条记录,第二个是 2 个,第三个只是 1 个。
Json :
[
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':44,
'name':'137'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':45,
'name':'138'
}
],
'id':61,
'name':'Garlaban'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':44,
'name':'137'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':45,
'name':'138'
}
],
'id':61,
'name':'Garlaban'
}
},
{
'end':1.5,
'begin':0.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':1.5,
'begin':0.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':43,
'name':'136'
},
{
'id':45,
'name':'138'
}
],
'id':131,
'name':'Régagnas'
}
},
{
'end':2.5,
'begin':1.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
}
]
什么是最好的解决方案?
谢谢
F.
据我了解,您的问题是,您希望按 begin
字段对所有内容进行分组。您尝试通过循环所有条目,然后再次循环所有条目(在列表理解中)来找到具有相同 begin
的条目,但外循环从它停止的地方继续。
相反,我建议使用 itertools.groupby
按该属性对条目进行分组。请注意,这假定条目按相同的属性排序,因此如果不是,请先对它们进行排序。
import csv, itertools, operator
with open("data.csv") as data:
prpk_by_highway = csv.DictReader(data)
for key, group in itertools.groupby(prpk_by_highway, key=operator.itemgetter("begin")):
print("BEGIN", key)
for prpk in group:
print(prpk)
此处,data.csv
是一个包含您的数据的 CSV 文件,也就是说,使用您的 tools_cronjob.getAPI
调用也应该可以使用。输出:
BEGIN 0
OrderedDict([('ID', '114'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '44'), ('report_id', '1')])
OrderedDict([('ID', '115'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '158'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '159'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '44'), ('report_id', '1')])
BEGIN 0.5
OrderedDict([('ID', '116'), ('begin', '0.5'), ('end', '1.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '117'), ('begin', '0.5'), ('end', '1.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
BEGIN 1.5
OrderedDict([('ID', '118'), ('begin', '1.5'), ('end', '2.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
或者,您可以使用 dict
将匹配的条目放入桶中。
我有一个内部循环和一个外部循环(数据库中的记录)。外循环(json)根据几个字段(例如:begin/end => 0 : 0.5 >>> ID 114 到 159)创建一个过滤器。
Table :
ID begin end status FK1_field FK2_field FK3_field FK4_field FK5_field report_id
114 0 0.5 1 NULL 13 8 142 44 1
115 0 0.5 1 NULL 13 8 61 45 1
158 0 0.5 1 NULL 13 8 142 45 1
159 0 0.5 1 NULL 13 8 61 44 1
116 0.5 1.5 1 NULL 13 8 142 45 1
117 0.5 1.5 1 NULL 13 8 131 45 1
118 1.5 2.5 1 NULL 13 8 142 45 1
结果在内部循环上循环(例如:4 records/lines (*))。
但是,当我退出内循环时,我必须在外循环上循环 4 次 (*) 以获得 ID 116(和过滤器 begin/end)=> 0.5 : 1.5.
的确,我可以只遍历内部循环并用 'if' 测试相同的几次。但我认为过滤更优雅。 现在,我认为退出内部循环时循环是愚蠢的。
代码:
highways = tools_cronjob.getAPI(API_URL + action, headers)
for highway in highways:
print('>>>>> Highway : %s ' % highway['name'])
# all the prpk, same values like the table
prpk_by_highway = tools_cronjob.getAPI(API_URL + actions_api['prpk_by_highway'] + "%s" % (highway['id']), headers)
# get all prpk by highway
for prpk in prpk_by_highway:
filtered_by_begin_end = [pr_pk for pr_pk in prpk_by_highway if pr_pk['begin'] == prpk['begin']]
# each couple of prpk 'begin' and 'end'
for filter_prpk in filtered_prpk_by_begin_end:
# some stuff
print (filter_prpk)
# when I exit, for eg, I must continue looping (prpk in prpk_by_highway) starting the couple begin/end : 0.5 : 1.5
所以第一个循环是 4 条记录,第二个是 2 个,第三个只是 1 个。 Json :
[
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':44,
'name':'137'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':45,
'name':'138'
}
],
'id':61,
'name':'Garlaban'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':0.5,
'begin':0.0,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':44,
'name':'137'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':45,
'name':'138'
}
],
'id':61,
'name':'Garlaban'
}
},
{
'end':1.5,
'begin':0.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
},
{
'end':1.5,
'begin':0.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':43,
'name':'136'
},
{
'id':45,
'name':'138'
}
],
'id':131,
'name':'Régagnas'
}
},
{
'end':2.5,
'begin':1.5,
'status':'1',
'department':{
'number':'13',
'id':13,
'name':'Bouches-du-Rhône'
},
'meteozone':{
'id':45,
'name':'138'
},
'commune':None,
'massif':{
'meteozones':[
{
'id':44,
'name':'137'
},
{
'id':45,
'name':'138'
},
{
'id':104,
'name':'831'
},
{
'id':105,
'name':'832'
}
],
'id':142,
'name':'Sainte-baume'
}
}
]
什么是最好的解决方案?
谢谢 F.
据我了解,您的问题是,您希望按 begin
字段对所有内容进行分组。您尝试通过循环所有条目,然后再次循环所有条目(在列表理解中)来找到具有相同 begin
的条目,但外循环从它停止的地方继续。
相反,我建议使用 itertools.groupby
按该属性对条目进行分组。请注意,这假定条目按相同的属性排序,因此如果不是,请先对它们进行排序。
import csv, itertools, operator
with open("data.csv") as data:
prpk_by_highway = csv.DictReader(data)
for key, group in itertools.groupby(prpk_by_highway, key=operator.itemgetter("begin")):
print("BEGIN", key)
for prpk in group:
print(prpk)
此处,data.csv
是一个包含您的数据的 CSV 文件,也就是说,使用您的 tools_cronjob.getAPI
调用也应该可以使用。输出:
BEGIN 0
OrderedDict([('ID', '114'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '44'), ('report_id', '1')])
OrderedDict([('ID', '115'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '158'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '159'), ('begin', '0'), ('end', '0.5'), ('status', '1'), ('FK', '44'), ('report_id', '1')])
BEGIN 0.5
OrderedDict([('ID', '116'), ('begin', '0.5'), ('end', '1.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
OrderedDict([('ID', '117'), ('begin', '0.5'), ('end', '1.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
BEGIN 1.5
OrderedDict([('ID', '118'), ('begin', '1.5'), ('end', '2.5'), ('status', '1'), ('FK', '45'), ('report_id', '1')])
或者,您可以使用 dict
将匹配的条目放入桶中。