我有一个这样的字典列表:
l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}]
,我想获得这种形式的输出:
>>> [('foo', 'bar'), ([1,2,3,4], [5,6,7,8])]
但是除了for
循环和append
之外,我看不到解决方案。有比这更聪明的方法吗?
names = []
values = []
for d in l:
names.append(d['name'])
values.append(d['values'])
答案 0 :(得分:29)
使用生成器表达式:
l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}]
v = [tuple(k["name"] for k in l), tuple(k["values"] for k in l)]
print(v)
输出:
[('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])]
答案 1 :(得分:24)
如果我编写此代码供公众使用,我将使用列表理解(与eyllanesc的类似)。但是,只是为了好玩,这是一种不使用任何for
的单线。
>>> l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}]
>>> list(zip(*map(dict.values, l)))
[('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])]
(请注意,这仅在字典保留插入顺序的情况下才能可靠地起作用,而在所有Python版本中并非如此。CPython3.6将其作为实现细节来实现,但仅从3.7起保证行为。)
该过程的快速细分:
dict_values
对象,该对象是一个可迭代的,包含dict的所有值。map
提取l
中的每个字典,并在其上调用dict.values,返回可迭代的dict_values对象。zip(*thing)
是一种经典的“换位”配方,它采用一个iterable-of-iterables并有效地将其对角翻转。例如。 [[a,b],[c,d]]变为[[a,c],[b,d]]。这会将所有名称放入一个元组,并将所有值放入另一个元组。list
将zip对象转换为列表。答案 2 :(得分:10)
您可以使用operator.itemgetter
来保证值的顺序:
from operator import itemgetter
fields = ('name', 'values')
res = list(zip(*map(itemgetter(*fields), L)))
print(res)
[('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])]
如果假设使用Python 3.6+,则不能保证字典在输入列表中的适当插入顺序,则需要显式定义上述顺序。
性能
虽然“元组理解”列表有效,但是当查询多个字段时,它变得不可读并且效率低下:
from operator import itemgetter
n = 10**6
L = [{'name': 'foo', 'values': [1,2,3,4], 'name2': 'zoo', 'name3': 'xyz',
'name4': 'def'}, {'name': 'bar', 'values': [5,6,7,8], 'name2': 'bart',
'name3': 'abc', 'name4': 'ghi'}] * n
%timeit [tuple(k["name"] for k in L), tuple(k["values"] for k in L),\
tuple(k["name2"] for k in L), tuple(k["name3"] for k in L),
tuple(k["name4"] for k in L)]
%timeit fields = ('name', 'values', 'name2', 'name3' ,'name4');\
list(zip(*map(itemgetter(*fields), L)))
1 loop, best of 3: 1.25 s per loop
1 loop, best of 3: 1.04 s per loop
答案 3 :(得分:5)
这可能与您的想法不完全相同,但是对于像这样的表格数据,我发现pandas
通常是长期最佳的解决方案:
>>> import pandas as pd
>>> l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}]
>>> df = pd.DataFrame(l)
name values
0 foo [1, 2, 3, 4]
1 bar [5, 6, 7, 8]
通常,您可以直接将数据框用于需要做的任何事情,但也可以将其转换为基于列表的数据结构:
>>> df['name'].tolist(), df['values'].tolist()
(['foo', 'bar'], [[1, 2, 3, 4], [5, 6, 7, 8]])
答案 4 :(得分:4)
不确定性能,但这是使用zip()
并解压缩的另一种方法:
list(zip(*[tuple(i.values()) for i in l]))
# [('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])]
编辑:正如@DeepSpace指出的那样,它可以进一步简化为:
list(zip(*(i.values() for i in l)))
如果您想自己定义订单,则这里的答案更长,但更明确:
list(zip(*(tuple(map(lambda k: i.get(k), ('name', 'values'))) for i in l)))
# [('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])]
答案 5 :(得分:3)
为此使用地图
names = tuple(map(lambda d: d['name'], l))
values = tuple(map(lambda d: d['values'], l))
result = [names, values]
答案 6 :(得分:0)
首先:您的代码精细,易读且高效,这对我来说听起来像是Pythonic。
请注意,尽管如此,您可能不想要元组列表。 Tuples are immutable,因此您将无法在names
后面加上其他名称。
如果names
是唯一的,则可以将字典列表转换为大字典:
>>> l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}]
>>> data = {d['name']:d['values'] for d in l}
>>> data
{'foo': [1, 2, 3, 4], 'bar': [5, 6, 7, 8]}
您可以直接获取所需的信息:
>>> data.keys()
dict_keys(['foo', 'bar'])
>>> data.values()
dict_values([[1, 2, 3, 4], [5, 6, 7, 8]])
如果您真的想要列表列表:
>>> [list(data.keys()), list(data.values())]
[['foo', 'bar'], [[1, 2, 3, 4], [5, 6, 7, 8]]]
如果要处理大量词典,则可能需要考虑pandas
。
您可以直接初始化DataFrame
:
>>> import pandas as pd
>>> df = pd.DataFrame([{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}])
>>> df
name values
0 foo [1, 2, 3, 4]
1 bar [5, 6, 7, 8]
如果需要将名称重复使用,则可以获取相应的列:
>>> df['name']
0 foo
1 bar
Name: name, dtype: object
如果您确实需要名称列表:
>>> list(df['name'])
['foo', 'bar']
要一起获取名称和值:
>>> df.values.T
array([['foo', 'bar'],
[list([1, 2, 3, 4]), list([5, 6, 7, 8])]], dtype=object)
答案 7 :(得分:0)
这是一种递归的方式:
def trans(l):
if l:
res = trans(l[1:])
res[0], res[1] = (l[0]['name'],) + res[0], (l[0]['values'],) + res[1]
return res
return [(),()]
答案 8 :(得分:-2)
就像这样:
>>> dexpires=time.strptime('20180823131455z','%Y%m%d%H%M%Sz')
>>> dexpires
time.struct_time(tm_year=2018, tm_mon=8, tm_mday=23, tm_hour=13, tm_min=14, tm_sec=55, tm_wday=3, tm_yday=235, tm_isdst=-1)
>>> time.strftime('%m/%d/%y',dexpires)
'08/23/18'
>>>
结果:
(lambda f:
lambda l, r=[(), ()]: f(f, l, r)
)(lambda g, l, r:
r if len(l) == 0 else g(g, l[1:], [r[0]+(l[0]['name'],), r[1]+(l[0]['values'],)])
)([
{'name': 'foo', 'values': [1, 2, 3, 4]},
{'name': 'bar', 'values': [5, 6, 7, 8]},
{'name': 'baz', 'values': [9, 9, 9, 9]}
])