在分隔符上拆分列表 - 将分隔符保留在组

时间:2015-11-11 11:18:02

标签: python dictionary

我有一个奇怪的数据结构,由我无法控制的外部服务返回给我。

这些数据基本上是一个字典列表,但却以一种奇怪的方式被删除:它作为字典列表返回,其中每个字典都有一个单个键。从该列表中取出多个元素会产生字典中的所有键。

在代码中:

[ {'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一些示例数据。

2 个答案:

答案 0 :(得分:0)

来自docs

  

每次键函数的值发生变化时,它(itertools.groupby)都会生成一个中断或新组。 。

从这个意义上说,itertools.groupbystr.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)])]