我有一个叫城市的csv文件,格式是这样的。
City_id,City,Population,Weather,State
la01,LA,24,72,CA
ny01,NY,12,42,NY
bo01,BO,32,65,BO
和另一个叫航运的csv文件。
Carrier,Type,Path,Packages,Max_Packages
UPS,Truck,la01-ny01,100,200
UPS,Truck,la01-bo01,100,200
UPS,Air,la01-ny01,100,500
UPS,Air,bo01-ny01,100,500
我需要把它们写成一个字符串,其中每一行都以城市开始,并有一个所有目的地的列表(该列表应按类型排序)。
la01:LA [Truck="ny01:100,200 + bo01:100,200" Air="ny01:100,500"];
bo01:BO [Air="ny01:100,500"];
我试图通过先把城市的cv文件读到一个字典里,然后抓取每个键(city_id)并把它存储在一个列表中,以便以后使用。我会使用城市id来匹配运输csv,并有一个循环,寻找所有的路径,从我当前迭代的任何城市id开始。从那里,我有if语句来检查Carrier,并打算将值拆分到Truck或Air字典中。然而,这个解决方案变得非常复杂,而且不能处理同一路径字符串可能出现多次的事实。有什么更简单的方法吗?
这只是一个读取CSV的问题,并把数据放到一个适合需要的报表输出的格式中。对于这一点,一个字典可以很容易地按城市对路线进行分组--用城市作为字典键。
import csv
from collections import defaultdict
from functools import partial
from operator import itemgetter
city_data = (r for r in csv.DictReader(open('city_data.csv', 'r')))
path_data = (r for r in csv.DictReader(open('path_data.csv', 'r')))
# Seems we only need city_data for id<=>city mapping. Simple dict works.
city_codes = {d['City_id']: d['City'] for d in city_data}
dest_data = defaultdict(partial(defaultdict, list))
package_data = itemgetter('Path', 'Type', 'Packages', 'Max_Packages')
for rec in path_data:
path, type, packages, max = package_data(rec)
city_id = path[:4]
city = city_codes[city_id]
dest_data[f'{city_id}:{city}'][type].append(f"{path[5:]}:{packages},{max}")
dest_data
然后包含。
defaultdict(...,
{
'la01:LA': defaultdict(<class 'list'>,
{
'Truck': ['ny01:100,200', 'bo01:100,200'],
'Air': ['ny01:100,500']
}),
'bo01:BO': defaultdict(<class 'list'>,
{
'Air': ['ny01:100,500']
})
})
现在你已经按照你的要求组织好了数据,只是像你的例子那样调整数据的显示方式。
>>> for city, pkg_routes in dest_data.items():
... pkg_info = (f'{type}="' + ' + '.join(pkg_list) + '"'
... for type, pkg_list in pkg_routes.items())
... print(f'{city} [' + ' '.join(pkg_info) + '];')
...
la01:LA [Truck="ny01:100,200 + bo01:100,200" Air="ny01:100,500"];
bo01:BO [Air="ny01:100,500"];
路径数据可以通过两个键来迭代和更新字典--这相当于一个组和子组:按城市和按路径类型。
使用 defaultdict
给我们提供了一个空列表,每当有新的键被添加到列表中时,就可以将路径信息添加到列表中,非常方便。
构建多级 defaultdict
是要通过一个 partial
对象作为其构造函数的参数。在 partial
可以设置为创建一个子defaultdict
按需生成新的列表。在这个例子中,当一个新的键被添加到列表中时,2-level dict会给我们一个空列表来追加路径信息。
itemgetter
是另一个方便的工具,它可以从列表中抓取多个键。path_data
字典,并返回一个元组的值。
最后一个关于良好实践的小说明。当指定一个理解(括号与方括号)时,使用一个生成器是很好的,因为这样可以减少算法中的循环次数。因此,在 path_data
CSV文件的访问与循环相结合,产生最终的字典。