如何将一个列表的列表转换为多层嵌套字典?

huangapple go评论77阅读模式
英文:

How to convert a list of lists into a multi-level nested dictionary?

问题

I want to convert a list of lists to multi-level nested dictionaries like so:

x = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]

print(f(x))
## {
##  1: {2: {3: 4,
##          4: 5}
##      },
##  5: {6: {7: 8}}    
## }

The list inside can be arbitrary long. Any ideas would be very helpful. For any set of nested keys, there is only one unique value possible. Thank you. So, the list mentioned below does not occur:

x = [[1,2,3,4],
     [1,2,3,5]]

I tried the function below but it throws an AttributeError: 'int' object has no attribute 'keys'.

Also, it updates incorrectly as mentioned below, so not very helpful.

def listoflists_dict(listformat):
    a = dict()
    cur = a
    for inner_list in listformat:
        for i, ele in enumerate(inner_list):
            print(a)
            if (ele not in cur.keys()) and (i < len(inner_list) - 1):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 1):
                cur[ele] = inner_list[-1]
            else:
                cur = cur[ele]
    
    return a

listformat = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]

listoflists_dict(listformat)

## {}
## {1: {}}
## {1: {2: {}}}
## {1: {2: {3: {}}}
## {1: {2: {3: {4: 4}}}
## {1: {2: {3: {4: 4, 1: {}}}}
## {1: {2: {3: {4: 4, 1: {2: {}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}
英文:

I want to convert a list of lists to multi-level nested dictionaries like so:

x = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]


print(f(x))
## {
##  1: {2: {3: 4,
##          4: 5}
##      },
##  5: {6: {7: 8}}    
## }

The list inside can be arbitrary long. Any ideas would be very helpful. For any set of nested keys, there is only one unique value possible. Thank you. So, the list mentioned below does not occur:

x = [[1,2,3,4],
     [1,2,3,5]]

I tried the function below but it throws an AttributeError: 'int' object has no attribute 'keys'.

Also, it updates incorrectly as mentioned below, so not very helpful.

def listoflists_dict(listformat):
    a = dict()
    cur = a
    for inner_list in listformat:
        for i, ele in enumerate(inner_list):
            print(a)
            if (ele not in cur.keys()) and (i < len(inner_list) - 1):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 1):
                cur[ele] = inner_list[-1]
            else:
                cur = cur[ele]
    
    return a

listformat = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]

listoflists_dict(listformat)

## {}
## {1: {}}
## {1: {2: {}}}
## {1: {2: {3: {}}}}
## {1: {2: {3: {4: 4}}}}
## {1: {2: {3: {4: 4, 1: {}}}}}
## {1: {2: {3: {4: 4, 1: {2: {}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {}}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}}

答案1

得分: 0

以下是翻译好的内容:

好主意,存在两个主要问题:

  • 你没有为每个 ele 重置 cur。将 cur = a 的位置下移一行将解决这个问题。
  • 需要特殊处理的元素是 len(inner_list) - 2,而不是 len(inner_list) - 1。你不应该处理 len(inner_list) - 1,所以使用 break 会很有用。

有了这些修改,你的代码如下所示:

def listoflists_dict(listformat):
    a = dict()
    for inner_list in listformat:
        cur = a
        for i, ele in enumerate(inner_list):
            if (ele not in cur.keys()) and (i < len(inner_list) - 2):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 2):
                cur[ele] = inner_list[-1]
                break
            else:
                cur = cur[ele]
    
    return a

现在,以下是一些非必要的注释:

  • ele not in cur.keys() 会顺序测试 cur 中的每个键,因为 cur.keys() 是一个生成器;ele not in cur 将直接测试字典中是否存在键,因此更可取。
  • 同样,{} 作为文字比必须调用函数的 dict() 更快。
  • 比起不得不检查它们,更容易将最后两个元素分离出来。

有了这些,这是一个更快和更简洁的版本:

def listoflists_dict(listformat):
    a = {}
    for *path, key, val in listformat:
        cur = a
        for ele in path:
            if ele not in cur:
                cur[ele] = {}
            cur = cur[ele]
        cur[key] = val
    return a
英文:

Good idea, with two major problems:

  • You don't reset cur for each ele. Moving cur = a one line down will fix this problem.
  • The element that needs special handling is len(inner_list) - 2, not len(inner_list) - 1. You must not process len(inner_list) - 1, so a break is useful.

With this, your code becomes:

def listoflists_dict(listformat):
    a = dict()
    for inner_list in listformat:
        cur = a
        for i, ele in enumerate(inner_list):
            if (ele not in cur.keys()) and (i &lt; len(inner_list) - 2):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 2):
                cur[ele] = inner_list[-1]
                break
            else:
                cur = cur[ele]
    
    return a

Now, several non-essential comments:

  • ele not in cur.keys() will sequentially test each key in cur, since cur.keys() is a generator; ele not in cur will directly test if a key is present in a dict, and should therefore be preferred
  • Similarly, {}, as a literal is faster than dict(), which must invoke a function
  • It is easier to tear off the last two elements, rather than having to check for them

With that, here is a faster and sleeker version:

def listoflists_dict(listformat):
    a = {}
    for *path, key, val in listformat:
        cur = a
        for ele in path:
            if ele not in cur:
                cur[ele] = {}
            cur = cur[ele]
        cur[key] = val
    return a

huangapple
  • 本文由 发表于 2023年3月23日 11:35:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75819045.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定