【问题标题】:Translate a table to a hierarchical dictionary?将表转换为分层字典?
【发布时间】:2012-04-28 21:51:46
【问题描述】:

我有一张表格:

A1, B1, C1, (value)
A1, B1, C1, (value)
A1, B1, C2, (value)
A1, B2, C1, (value)
A1, B2, C1, (value)
A1, B2, C2, (value)
A1, B2, C2, (value)
A2, B1, C1, (value)
A2, B1, C1, (value)
A2, B1, C2, (value)
A2, B1, C2, (value)
A2, B2, C1, (value)
A2, B2, C1, (value)
A2, B2, C2, (value)
A2, B2, C2, (value)

我想在 python 中使用它作为字典,形式为:

H = {
    'A1':{
        'B1':{
            'C1':[],'C2':[],'C3':[] },
        'B2':{
            'C1':[],'C2':[],'C3':[] },
        'B3':{
            'C1':[],'C2':[],'C3':[] }
    },
    'A2':{
        'B1':{
            'C1':[],'C2':[],'C3':[] },
        'B2':{
            'C1':[],'C2':[],'C3':[] },
        'B3':{
            'C1':[],'C2':[],'C3':[] }
    }
}

这样H[A][B][C] 会产生一个特定的唯一值列表。对于小型字典,我可能只是像上面那样提前定义结构,但我正在寻找一种有效的方法来遍历表并构建字典,而无需提前指定字典键。

【问题讨论】:

  • 您是否总是查找三元组的 A、B、C 值?如果是这样,您最好使用单个 dict 并使用这些三元组作为键。

标签: python dictionary nested


【解决方案1】:
input = [('A1', 'B1', 'C1', 'Value'), (...)]

from collections import defaultdict

tree = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
#Alternatively you could use partial() rather than lambda:
#tree = defaultdict(partial(defaultdict, partial(defaultdict, list)))

for x, y, z, value in input:
    tree[x][y][z].append(value)

【讨论】:

  • 请注意,如果 table 是文本文件,您将需要类似 with open("table") as file: input = [line.split() for line in file] 的内容。
  • 这里使用 lambdas 的替代方法是使用 functools.partial(): tree = defaultdict(partial(defaultdict, partial(defaultdict, list))) - 我觉得这更清楚,但可能只是我自己。
【解决方案2】:
d = {}
for (a, b, c, value) in your_table_of_tuples:
   d.setdefault(a, {}).setdefault(b,{}).setdefault(c,[]).append(value)

【讨论】:

  • 为什么使用setdefault() 而不是defaultdict
  • 我认为当你使用它时它会更丑。
  • 这就是我在 cmets 中提供基于 functools.partial() 的解决方案的原因。 ;)(为了便于阅读,可以展开)。
【解决方案3】:

如果您只访问 H[A][B][C](即,永远不会单独访问 H[A] 或 H[A][B]),我建议使用 IMO 更清洁的解决方案:使用元组作为默认字典索引:

from collections import defaultdict
h = defaultdict(list)
for a, b, c, value in input:
    h[a, b, c].append(value)

【讨论】:

  • 这也是一个非常有效(且优雅)的解决方案,尽管它确实要求他不想单独访问子字典。 (编辑删除了一些额外的缩进、不需要的括号和 PEP-8 化变量名)。
  • 感谢您发布此解决方案。在这种情况下,我需要访问子词典,但我没有在问题中指定。如果将来存在这种情况,这将非常优雅。
【解决方案4】:

但是,如果您没有三个级别,而是可能有十个级别怎么办?很确定你可以用一个while循环来做到这一点,但这就是我想出的(警告:对可变性和指针的极端利用)

def build_tree(data, categories):
    """Build a dependency tree based on a Pandas DataFrame and an
    ordered list of levels.

    Parameters
    ----------
    data : pandas.core.frame.DataFrame
        A DataFrame containing the table to derive tree from
    categories : array_like
        An ordered, sliceable list of column names to include in tree

    Returns
    -------
    hierarchy : dict
        A standard Python dictionary
        """
    hierarchy = {}
    def expand(data, categories, current_level):
        if len(categories) == 2:
            for value in data[categories[0]].unique():
                current_level[value] = data.loc[data[categories[0]] == value, categories[1]]
        else:
            for value in data[categories[0]].unique():
                current_level[value] = {e: None for e in data.loc[data[categories[0]] == value, categories[1]].unique()}
                expand(data.loc[data[categories[0]] == value, :], categories[1:], current_level[value])
    expand(data, categories, hierarchy)
    return hierarchy

我觉得有些 for 循环可能会更好,但不是总是这样吗?

这还取决于在您的层次结构底部找到的单个键/值对。

【讨论】:

    【解决方案5】:

    这适用于任意数量的键:

    def parse_table_to_tree(table):
        tree = dict()
        for row in table:
            tree = attach_leaf(tree, row[:-1], row[-1])
        return tree
    
    
    def attach_leaf(tree:dict, keys:list, value):
        d = tree
        for i, key in enumerate(keys):
            if i < len(keys)-1:
                d = d.setdefault(key, {})
            else:
                d[key] = value
        return tree
    
    tree = parse_table_to_tree(
        [
            ['a', 'b', 'c', []],
            ['a', 'b', 'd', []],
            ['a', 'f', 'a', []]
        ]
    )
    

    【讨论】:

      猜你喜欢
      • 2020-10-07
      • 2023-01-12
      • 1970-01-01
      • 2020-09-23
      • 2018-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多