整理列表的字典(深度为2级)

问题描述 投票:5回答:3

我正在尽我所能,但还不够灵活。

在我的Python脚本中,我有一个字典字典列表。 (实际上,它会更深入一点,但该级别不涉及此问题。)我想将所有这些内容整理成一个长长的列表,并丢弃所有字典键。

因此我要转换

{1: {'a': [1, 2, 3], 'b': [0]},
 2: {'c': [4, 5, 1], 'd': [3, 8]}}

to

[1, 2, 3, 0, 4, 5, 1, 3, 8]

我可能可以设置map-reduce来迭代外部字典的项,以从每个子词典构建子列表,然后将所有子列表连接在一起。

但是对于大型数据集,这似乎效率不高,因为中间的数据结构(子列表)将被丢弃。有没有一种方法可以一次性完成?

除非,我很乐意接受一个有效的两级实现...我的map-reduce生锈了!

更新:对于那些感兴趣的人,下面是我最终使用的代码。

[请注意,尽管我在上面要求输出一个列表,但我真正需要的是排序列表;即,拼合的输出可以是任何可排序的可迭代。

def genSessions(d):
    """Given the ipDict, return an iterator that provides all the sessions,
    one by one, converted to tuples."""
    for uaDict in d.itervalues():
        for sessions in uaDict.itervalues():
            for session in sessions:
                yield tuple(session)

...

# Flatten dict of dicts of lists of sessions into a list of sessions.
# Sort that list by start time
sessionsByStartTime = sorted(genSessions(ipDict), key=operator.itemgetter(0))
# Then make another copy sorted by end time.
sessionsByEndTime = sorted(sessionsByStartTime, key=operator.itemgetter(1))

再次感谢所有提供帮助的人。

[[更新:由于@intuited而用nthGetter()替换了operator.itemgetter()。]

python data-structures mapreduce dictionary
3个回答
6
投票

edit:重新阅读原始问题和重新设计的答案,以假定所有非字典都是要扁平化的列表。

[如果您不确定字典的使用范围,可以使用递归函数。 @Arrieta已经具有posted一个以递归方式建立非字典值列表的函数。

这是一个在字典树中产生连续非字典值的生成器:

def flatten(d):
    """Recursively flatten dictionary values in `d`.

    >>> hat = {'cat': ['images/cat-in-the-hat.png'],
    ...        'fish': {'colours': {'red': [0xFF0000], 'blue': [0x0000FF]},
    ...                 'numbers': {'one': [1], 'two': [2]}},
    ...        'food': {'eggs': {'green': [0x00FF00]},
    ...                 'ham': ['lean', 'medium', 'fat']}}
    >>> set_of_values = set(flatten(hat))
    >>> sorted(set_of_values)
    [1, 2, 255, 65280, 16711680, 'fat', 'images/cat-in-the-hat.png', 'lean', 'medium']
    """
    try:
        for v in d.itervalues():
            for nested_v in flatten(v):
                yield nested_v
    except AttributeError:
        for list_v in d:
            yield list_v

doctest将结果迭代器传递给set函数。这很可能就是您想要的,因为正如Martelli先生所指出的那样,字典值没有内在顺序,因此没有理由跟踪它们的查找顺序。

您可能希望跟踪每个值的出现次数;如果将迭代器传递给set,则此信息将丢失。如果要跟踪,只需将flatten(hat)的结果传递给其他功能而不是set。在Python 2.7下,该其他函数可以为collections.Counter。为了与发展较慢的python兼容,您可以编写自己的函数或(在效率方面有所损失)将sorteditertools.groupby结合使用。


17
投票

我希望您意识到,您在词典中看到的任何订单都是偶然的-只是因为在屏幕上显示时,必须选择some订单,但绝对不能保证。

链接的各个子列表之间的订购问题净额,

[x for d in thedict.itervalues()
   for alist in d.itervalues()
   for x in alist]

做您想做的事而没有任何效率低下或中间的列表。


6
投票

递归函数可能起作用:

def flat(d, out=[]):
 for val in d.values():
  if isinstance(val, dict):
    flat(d, out)
  else:
    out+= val

如果您尝试使用:

>>> d = {1: {'a': [1, 2, 3], 'b': [0]}, 2: {'c': [4, 5, 6], 'd': [3, 8]}}
>>> out = []
>>> flat(d, out)
>>> print out
[1, 2, 3, 0, 4, 5, 6, 3, 8]

注意,字典没有顺序,因此列表是随机的。

您也可以return out(在循环的结尾),并且不要使用列表参数调用该函数。

def flat(d, out=[]):
 for val in d.values():
  if isinstance(val, dict):
    flat(d, out)
  else:
    out+= val
 return out

称为:

my_list = flat(d)
© www.soinside.com 2019 - 2024. All rights reserved.