基于元组值的嵌套字典的元组列表
List of tuples to nested dictionary based on tuple's values
给定一个元组列表,例如
[(1, 'Japan', 1, 'Tokyo'), (1, 'Japan', 2, 'Osaka'), (2, 'Korea', 1, 'Seoul',), (2, 'Korea', 2, 'Pyongyang')]
# country_id, country_name, city_id, city_name
我希望将其结构化为:
{
'countries': [
{
'country_id': 1,
'country_name': 'Japan',
'cities': [
{
'city_id': 1,
'city_name': 'Tokyo'
},
{
'city_id': 2,
'city_name': 'Osaka'
}
]
},
{
'country_id': 2,
'country_name': 'Korea',
'cities': [
{
'city_id': 1,
'city_name': 'Seoul'
},
{
'city_id': 2,
'city_name': 'Pyongyang'
}
]
}
]
}
我实现了它并且运行良好,但不是 Pythonic。想知道这是否可以大大提高 refined/sped,因为这形成了 API 的响应。
x = [(1, 'Japan', 1, 'Tokyo'), (1, 'Japan', 2, 'Osaka'), (2, 'Korea', 1, 'Seoul'), (2, 'Korea', 2, 'Pyongyang')]
countrylist = []
query_countries = []
for a in x:
if a[0] not in countrylist:
query_countries.append((a[0], a[1]))
countrylist.append(a[0])
countrylist = list(set(countrylist))
countries = [{'country_id': r[0], 'country_name': r[1], 'cities': []} for r in query_countries]
for r in x:
countries[countrylist.index(r[0])]['cities'].append({'city_id': r[2], 'city_name': r[3]})
final = {'countries': countries}
print(final)
#{'countries': [{'country_id': 1, 'country_name': 'Japan', 'cities': [{'city_id': 1, 'city_name': 'Tokyo'}, {'city_id': 2, 'city_name': 'Osaka'}]}, {'country_id': 2, 'country_name': 'Korea', 'cities': [{'city_id': 1, 'city_name': 'Seoul'}, {'city_id': 2, 'city_name': 'Pyongyang'}]}]}
表达式a[0] not in countrylist
和countrylist.index(r[0])
不是最有效的,因为countrylist
是一个列表,这些操作需要扫描列表。在某些时候你把它变成一个集合,但你可以决定从头到尾都使用一个集合,然后这些查找操作可以在恒定时间内(平均)完成。这已经可以提高大输入的性能。
对于这种挑战,groupby
和 itemgetter
似乎是很好的工具。他们允许用一个表达式完成工作:
data = [(1, 'Japan', 1, 'Tokyo'), (1, 'Japan', 2, 'Osaka'), (2, 'Korea', 1, 'Seoul',), (2, 'Korea', 2, 'Pyongyang')]
from itertools import groupby
from operator import itemgetter
result = [
{
"country_id": country_id,
"country_name": country_name,
"cities": [
{
"city_id": city_id,
"city_name": city_name
} for *_, city_id, city_name in cities
]
} for (country_id, country_name), cities in groupby(data, itemgetter(0, 1))
]
print(result)
groupby
你可以想象这个 groupby
调用 return 这个结构:
[
(1, 'Japan'), [
(1, 'Japan', 1, 'Tokyo'),
(1, 'Japan', 2, 'Osaka')
],
(2, 'Korea'), [
(2, 'Korea', 1, 'Seoul'),
(2, 'Korea', 2, 'Pyongyang')
]
]
...除了列表不是列表而是迭代器。但是对于 for ... in
没有区别的语法。
内部元组只是对原始数据的引用,而外层(组)中的值由 itemgetter
生成,它生成前两个值的元组。