我有一个奇怪的数据结构,由我无法控制的外部服务返回给我。
这些数据基本上是一个字典列表,但却以一种奇怪的方式被删除:它作为字典列表返回,其中每个字典都有一个单个键。从该列表中取出多个元素会产生字典中的所有键。
在代码中:
[ {'id': 1}, {'a': a}, {'b': b}, {'c': c},
{'id': 2}, {'a': a}, {'b': b}, {'c': c},
{'id': 3}, {'a': a}, {'b': b}, {'c': c},
...
]
我想要重构的每个字典都以id
字典开头。找到id
密钥后,我需要从列表中获取所有值,直到找到另一个id
。
我目前的解决方案是:
def split_groups(data, key='id'):
groups = []
for e in data:
if key in e: # begin new group
groups.append(list())
groups[-1].append(e)
return groups
哪个有效,但很难看。我知道itertools.groupby
:但是,我真的不明白如何使用它。
这一行的结果:
[(k, list(g)) for k, g in groupby(data, lambda d: d.get('id') is not None)]
是:
[(True, [{'id': 1}]),
(False, [{'a': 1}, {'b': 2}, {'c': 3}]),
(True, [{'id': 2}]),
(False, [{'a': 1}, {'b': 2}, {'c': 3}]),
(True, [{'id': 3}]),
(False, [{'a': 1}, {'b': 2}, {'c': 3}])]
正如您所看到的,id
字典最终位于与以下值不同的组中。
我做错了什么?
在Sumukh Barve的回答之后,我猜这个组合并不适合我的工作。我目前的代码将用于生产;只是为了好玩,我重写了这样:
def split_groups(data, key='id'):
if not data:
return []
predicate = lambda d: key not in d
head, tail = data[0], data[1:]
group = [[head] + list(takewhile(predicate, tail))]
rest = list(dropwhile(predicate, tail))
group.extend(split_groups(rest, key))
return group
这是一种效率低得多,可读性低得多,更具吸引力的吸引力形式。
感谢大家的帮助!
如果有人有一天会遇到同样的问题,我会附上the full solution一些示例数据。
答案 0 :(得分:0)
来自docs:
每次键函数的值发生变化时,它(
itertools.groupby
)都会生成一个中断或新组。 。
从这个意义上说,itertools.groupby
与str.split
类似;不同之处在于分割序列也包含在输出中。
"1,2,3".split(",") ==> ["1", "2", "3"]
"1,2,3".splitLikeGroupBy(",") ==> ["1", ",", "2", ",", "3"]
所以,你没有做错任何事。
另外,我说你的解决方案很好。
但是,如果您坚持使用itertools.groupby
,请尝试以下操作:
a = [(k, list(g)) for k, g in groupby(data, lambda d: d.get('id') is not None)];
[a[i][1] + a[i+1][1] for i in range(len(a)) if i % 2 == 0]
第一行直接来自您的代码。第二个是一些简单的处理。
<强>建议:强>
您可能希望使用多元素词典列表,而不是使用单元素词典列表的列表。
也就是说,而不是使用它:
[
[{"id": "id1"}, {"a": "a1"}],
[{"id": "id2"}, {"a": "a2"}], ...
]
您可能想要使用此功能:
[
{"id": "id1", "a": "a1"},
{"id": "id2", "a": "a2"}, ...
]
希望这会有所帮助。
答案 1 :(得分:0)
ind=[i for i,d in enumerate(l) if 'id' in d]
slices=[l[a:b] for (a,b) in zip(ind,ind[1:]+[len(l)])]