将嵌套的命名元组列表展平为字典列表
Flatten list of nested namedtuples to list of dictionaries
样本:
import collections
A = collections.namedtuple('A', 'a b c')
B = collections.namedtuple('B', 'x y z w')
L = [A(a='CODE1', b=B(x=2, y='u', z='v', w='a'), c=10),
A(a='CODE2', b=B(x=4, y='h', z='r', w='b'), c=30)]
我有 namedtuple 列表,我想将其展平,将嵌套的 namedtuple B
替换为 b
.
的值
我的尝试:
首先,我尝试将两个命名元组转换为字典并合并它们,但问题是删除了字典理解中的原始 b
值,而且顺序错误:
t = [{k: v for k, v in {**x.b._asdict(), **x._asdict()}.items()
if k != 'b'} for x in L]
print (t)
[{'x': 2, 'y': 'u', 'z': 'v', 'w': 'a', 'a': 'CODE1', 'c': 10},
{'x': 4, 'y': 'h', 'z': 'r', 'w': 'b', 'a': 'CODE2', 'c': 30}]
另一种解决方案符合需要,但我认为它有点复杂 - 我更喜欢列表理解解决方案:
t = []
for x in L:
out = {}
d = x._asdict()
for k, v in d.items():
if isinstance(v, tuple):
d1 = v._asdict()
for k1, v1 in d1.items():
out[k1] = v1
else:
out[k] = v
t.append(out)
print (t)
[{'a': 'CODE1', 'x': 2, 'y': 'u', 'z': 'v', 'w': 'a', 'c': 10},
{'a': 'CODE2', 'x': 4, 'y': 'h', 'z': 'r', 'w': 'b', 'c': 30}]
具有复杂的 list
理解和 OrderedDict
对象:
from collections import namedtuple, OrderedDict
from itertools import chain
...
res = [OrderedDict(chain.from_iterable(
v._asdict().items() if isinstance(v, (A, B)) else [(k, v)]
for k, v in nt._asdict().items())) for nt in L]
print(res)
输出:
[OrderedDict([('a', 'CODE1'),
('x', 2),
('y', 'u'),
('z', 'v'),
('w', 'a'),
('c', 10)]),
OrderedDict([('a', 'CODE2'),
('x', 4),
('y', 'h'),
('z', 'r'),
('w', 'b'),
('c', 30)])]
"trick"是获取一个flat的元组序列传递给OrderedDict(...)
(顶层元组被包裹[(k, v)]
到同意 潜在的嵌套元组)
据我所知,字典中没有排序。如果排序对您很重要,您可以考虑使用 Collections 包中的 OrderedDict(请参阅 manual)。顺便说一句,namedtuples 似乎是建立在 OrderedDicts 之上的...
关于您的问题,也许您可以创建另一种类型的命名元组来强制执行您的命令:
AB = collections.namedtuple('AB', 'a x y z w c')
然后您可以根据需要显式转码:
list(map( lambda l: AB(l.a, l.b.x, l.b.y, l.b.z, l.b.w, l.c) , L))
如果出于某种原因您不想显式写入 B 的字段,您可以使用
进行一些自动化
AB(L[0].a,*[v for v in L[0].b._asdict()],L[0].c)
编辑以嵌入评论和对评论的回答------------
import collections
from itertools import chain
A = collections.namedtuple('A', 'a b c')
B = collections.namedtuple('B', 'x y z w')
L = [A(a='CODE1', b=B(x=2, y='u', z='v', w='a'), c=10),
A(a='CODE2', b=B(x=4, y='h', z='r', w='b'), c=30)]
AB = collections.namedtuple('AB',
" ".join(chain.from_iterable(
v._asdict().keys() if isinstance(v, (A, B)) else [k] for k,v in L[0]._asdict().items())
)
)
LL = [AB._make(dict(
chain.from_iterable(
v._asdict().items() if isinstance(v, (A, B)) else [(k, v)] for k, v in nt._asdict().items())
)) for nt in L]
print (LL)
目前我只能看到这些,希望对您有所帮助。
样本:
import collections
A = collections.namedtuple('A', 'a b c')
B = collections.namedtuple('B', 'x y z w')
L = [A(a='CODE1', b=B(x=2, y='u', z='v', w='a'), c=10),
A(a='CODE2', b=B(x=4, y='h', z='r', w='b'), c=30)]
我有 namedtuple 列表,我想将其展平,将嵌套的 namedtuple B
替换为 b
.
我的尝试:
首先,我尝试将两个命名元组转换为字典并合并它们,但问题是删除了字典理解中的原始 b
值,而且顺序错误:
t = [{k: v for k, v in {**x.b._asdict(), **x._asdict()}.items()
if k != 'b'} for x in L]
print (t)
[{'x': 2, 'y': 'u', 'z': 'v', 'w': 'a', 'a': 'CODE1', 'c': 10},
{'x': 4, 'y': 'h', 'z': 'r', 'w': 'b', 'a': 'CODE2', 'c': 30}]
另一种解决方案符合需要,但我认为它有点复杂 - 我更喜欢列表理解解决方案:
t = []
for x in L:
out = {}
d = x._asdict()
for k, v in d.items():
if isinstance(v, tuple):
d1 = v._asdict()
for k1, v1 in d1.items():
out[k1] = v1
else:
out[k] = v
t.append(out)
print (t)
[{'a': 'CODE1', 'x': 2, 'y': 'u', 'z': 'v', 'w': 'a', 'c': 10},
{'a': 'CODE2', 'x': 4, 'y': 'h', 'z': 'r', 'w': 'b', 'c': 30}]
具有复杂的 list
理解和 OrderedDict
对象:
from collections import namedtuple, OrderedDict
from itertools import chain
...
res = [OrderedDict(chain.from_iterable(
v._asdict().items() if isinstance(v, (A, B)) else [(k, v)]
for k, v in nt._asdict().items())) for nt in L]
print(res)
输出:
[OrderedDict([('a', 'CODE1'),
('x', 2),
('y', 'u'),
('z', 'v'),
('w', 'a'),
('c', 10)]),
OrderedDict([('a', 'CODE2'),
('x', 4),
('y', 'h'),
('z', 'r'),
('w', 'b'),
('c', 30)])]
"trick"是获取一个flat的元组序列传递给OrderedDict(...)
(顶层元组被包裹[(k, v)]
到同意 潜在的嵌套元组)
据我所知,字典中没有排序。如果排序对您很重要,您可以考虑使用 Collections 包中的 OrderedDict(请参阅 manual)。顺便说一句,namedtuples 似乎是建立在 OrderedDicts 之上的...
关于您的问题,也许您可以创建另一种类型的命名元组来强制执行您的命令:
AB = collections.namedtuple('AB', 'a x y z w c')
然后您可以根据需要显式转码:
list(map( lambda l: AB(l.a, l.b.x, l.b.y, l.b.z, l.b.w, l.c) , L))
如果出于某种原因您不想显式写入 B 的字段,您可以使用
进行一些自动化AB(L[0].a,*[v for v in L[0].b._asdict()],L[0].c)
编辑以嵌入评论和对评论的回答------------
import collections
from itertools import chain
A = collections.namedtuple('A', 'a b c')
B = collections.namedtuple('B', 'x y z w')
L = [A(a='CODE1', b=B(x=2, y='u', z='v', w='a'), c=10),
A(a='CODE2', b=B(x=4, y='h', z='r', w='b'), c=30)]
AB = collections.namedtuple('AB',
" ".join(chain.from_iterable(
v._asdict().keys() if isinstance(v, (A, B)) else [k] for k,v in L[0]._asdict().items())
)
)
LL = [AB._make(dict(
chain.from_iterable(
v._asdict().items() if isinstance(v, (A, B)) else [(k, v)] for k, v in nt._asdict().items())
)) for nt in L]
print (LL)
目前我只能看到这些,希望对您有所帮助。