简体   繁体   中英

Generate a nested dictionary from list

I want to populate a nested dictionary in python3 but I'm at a loss as to how to do this cleanly. I want to have an update function that works in the following way:

#pseudo code for the update given One and Two:
One = ('W/X/Y/Z.py', 1, 8)
Two = ('A/B/C/D.py', 12, 42)

#blank initialization
Dict = dict()

#structure gets created based on the path in Two
def updateDict(One, Two):
    tuple = (1, 8, 12, 42)
    try:
        Dict["A"]["B"]["C"]["D.py"]['W/X/Y/Z.py'].append(tuple)
    except:
        Dict["A"]["B"]["C"]["D.py"]['W/X/Y/Z.py'] = [tuple]
#where:
#Dict["A"] is now a dict, 
#Dict["A"]["B"] is now a dict, 
#Dict["A"]["B"]["C"] is now a dict and 
#Dict["A"]["B"]["C"]["D.py"] is now a dict
#Dict["A"]["B"]["C"]["D.py"]["W/X/Y/Z.py"] is now a list of tuples with four values

Iteratively given
One = ('W/X/Y/Z.py', 1, 8)
Two = ('A/B/C/D.py', 12, 42)

One = ('W/X/Y/Z.py', 50, 60)
Two = ('A/B/C/D.py', 90, 100)

One = ('W/X/Y/NOTZ.py', 3, 14)
Two = ('A/B/C/D.py', 15, 22)

One = ('W/X/Y/Z.py', 14, 62)
Two = ('A/B/C/NOTD.py', 13, 56)
#Would produce the following structure:
Dict = 
{"A":   {
        "B":    {
                "C":    {
                        "D.py": {
                                "W/X/Y/Z.py" : [(1,8,12,42), (50,60,90,100)],
                                "W/X/Y/NOTZ.py" : [(3,14,15,22)]
                        },
                        "NOTD.py": {
                                "W/X/Y/Z.py" : [(14,62,13,56)]
                        }
                }
        }
}}
This can be made using the following commands:
Dict = dict()
Dict["A"] = dict()
Dict["A"]["B"] = dict()
Dict["A"]["B"]["C"] = dict()
Dict["A"]["B"]["C"]["D.py"] = dict()
Dict["A"]["B"]["C"]["D.py"]["W/X/Y/Z.py"] = [(1,8,12,42), (50,60,90,100)]
Dict["A"]["B"]["C"]["D.py"]["W/X/Y/NOTZ.py"] = [(3,14,15,22)]
Dict["A"]["B"]["C"]["NOTD.py"] = dict()
Dict["A"]["B"]["C"]["NOTD.py"]["W/X/Y/Z.py"] = [(14,62,13,56)]

so Dict["A"]["B"]["C"] would return a dictionary:

dict(
    "D.py": {
        "W/X/Y/Z.py" : [(1,8,12,42), (50,60,90,100)],
        "W/X/Y/NOTZ.py" : [(3,14,15,22)]
     },
    "NOTD.py": {
        "W/X/Y/Z.py" : [(14,62,13,56)]
    }
)

and Dict["A"]["B"]["C"]["D.py"] would return a dictionary:

dict(
    "W/X/Y/Z.py" : [(1,8,12,42), (50,60,90,100)],
    "W/X/Y/NOTZ.py" : [(3,14,15,22)]
)

and Dict["A"]["B"]["C"]["D.py"]["W/X/Y/Z.py"] would return a list of tuples:

[(1,8,12,42), (50,60,90,100)]

So all the nested values are dictionaries but all of the leaves are lists of tuples.

The paths in the strings in One and Two can both be arbitrary length and values before ending in a filename (so you could get W/X/Y/Z.py or W/X/AA.py or Q/R/S/T/U/V.py).

Any packages that might aid in this would be appreciated.

Here's one version of updateDict() that does what you want (note: Py3). It uses a pointer d into the arbitrary depth dictionary and then just appends the tuple to that pointer:

Dict = dict()

def updateDict(One, Two):
    k, *v1 = One
    path, *v2 = Two
    d = Dict
    for p in path.split('/'):
        d = d.setdefault(p, {})
    d.setdefault(k, []).append(tuple(v1+v2))

In []:
One = ('W/X/Y/Z.py', 1, 8)
Two = ('A/B/C/D.py', 12, 42)
updateDict(One, Two)
Dict

Out[]:
{'A': {'B': {'C': {'D.py': {'W/X/Y/Z.py': [(1, 8, 12, 42)]}}}}}

In []:
One = ('W/X/Y/Z.py', 50, 60)
Two = ('A/B/C/D.py', 90, 100)
updateDict(One, Two)
Dict

Out[]:
{'A': {'B': {'C': {'D.py': {'W/X/Y/Z.py': [(1, 8, 12, 42), (50, 60, 90, 100)]}}}}}

Etc...

It's hard to understand what your are doing. But let me try to describe what do you need to do.

Dict = {}
Dict.setdefault('A', {})
Dict['A'].setdefault('B', {})
Dict['A']['B'].setdefault('C', {})
Dict['A']['B']['C'].setdefault('D.py', {})
Dict['A']['B']['C']['D.py'].setdefault('W/X/Y/Z.py', set())
Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'].add(???)

Another point you need to know, set can't add a list. You can only add a number, or a tuple —— which is immutable. So the last step you should do below:

Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'] = Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'].union([1, 8, 12, 42]).union([50, 60, 90, 100])
# {1, 8, 12, 42, 50, 60, 90, 100}
# or
Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'].add((1, 8, 12, 42))
Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'].add((50, 60, 90, 100))
# {(1, 8, 12, 42), (50, 60, 90, 100)}

OK, I see you have edited the last step. So it's easier now.

Dict = {}
Dict.setdefault('A', {})
Dict['A'].setdefault('B', {})
Dict['A']['B'].setdefault('C', {})
Dict['A']['B']['C'].setdefault('D.py', {})
Dict['A']['B']['C']['D.py'].setdefault('W/X/Y/Z.py', [])
Dict['A']['B']['C']['D.py']['W/X/Y/Z.py'].append(tuple)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM