Home > Net >  How to display multiple values in a nested dictionary in python?
How to display multiple values in a nested dictionary in python?

Time:06-11

I am tasked with creating a nested dictionary, using a comprehension to display the result while using the given list.

For example, given input like

given_list = ['iCLA', 'YGU', 'icla YGU', 'Hello World', 'Python']

the code should produce:

{'iCLA': {'UPPER': ['C', 'L', 'A'], 'lower': ['i']},    
'YGU': {'UPPER': ['Y', 'G', 'U'], 'lower': []},    
'icla YGU': {'UPPER': ['Y', 'G', 'U'], 'lower': ['i', 'c', 'l', 'a']},    
'Hello World': {'UPPER': ['H', 'W'],    
'lower': ['e', 'l', 'l', 'o', 'o', 'r', 'l', 'd']},    
'Python': {'UPPER': ['P'], 'lower': ['y', 't', 'h', 'o', 'n']}}

The nested section confused me. I think I should use an if condition to check each letter and place it in a list, but it didn't work for me. How can I write the code?

CodePudding user response:

You can use a O(n) solution by traversing all the letters on each word and checking whether they are lower or upper like this:

l = ['iCLA', 'YGU', 'icla YGU', 'Hello World', 'Python']
d = {}

for i in l:
    up, low = [], []
    for a in i:
        if a.islower():
            low.append(a)
        else:
            up.append(a)
    d[i] = {"UPPER":up, "lower":low}
print(d)

Output:

{'iCLA': {'UPPER': ['C', 'L', 'A'], 'LOWER': ['i']}, 'YGU': {'UPPER': ['Y', 'G', 'U'], 'LOWER': []}, 'icla YGU': {'UPPER': [' ', 'Y', 'G', 'U'], 'LOWER': ['i', 'c', 'l', 'a']}, 'Hello World': {'UPPER': ['H', ' ', 'W'], 'LOWER': ['e', 'l', 'l', 'o', 'o', 'r', 'l', 'd']}, 'Python': {'UPPER': ['P'], 'LOWER': ['y', 't', 'h', 'o', 'n']}}

CodePudding user response:

It can be done. It loses some efficiency due to checking each character twice, but coefficient loses are no big deal.

d = {
    x: {"UPPER": [c for c in x if c.isupper()], "LOWER": [c for c in x if c.islower()]}
    for x in given_list
}
print(d)

output:

{'iCLA': {'UPPER': ['C', 'L', 'A'], 'LOWER': ['i']}, 'YGU': {'UPPER': ['Y', 'G', 'U'], 'LOWER': []}, 'icla YGU': {'UPPER': ['Y', 'G', 'U'], 'LOWER': ['i', 'c', 'l', 'a']}, 'Hello World': {'UPPER': ['H', 'W'], 'LOWER': ['e', 'l', 'l', 'o', 'o', 'r', 'l', 'd']}, 'Python': {'UPPER': ['P'], 'LOWER': ['y', 't', 'h', 'o', 'n']}}

One might think you could improve the time with defaultdict, but it actually slows it down a bit, even though the character check only happens once per character. However, your best bet is just plain ol' normal loop structure. Comprehension are awesome, but there are cases where it doesn't make sense.

Here you can see the times:

from collections import defaultdict
from statistics import fmean
import timeit

given_list = ["iCLA", "YGU", "icla YGU", "Hello World", "Python"]


def with_comp(l):
    return {
        x: {
            "UPPER": [c for c in x if c.isupper()],
            "LOWER": [c for c in x if c.islower()],
        }
        for x in given_list
    }


def with_defaultdict(l):
    d = {}
    for x in given_list:
        d[x] = defaultdict(list)
        for c in x:
            d[x]["UPPER"].append(c) if c.isupper() else d[x]["lower"].append(c)
        d[x] = dict(d[x])
    return d

def plain(l):
    d = {}
    for x in given_list:
        d[x] = {"UPPER": [], "lower": []}
        for c in x:
            d[x]["UPPER"].append(c) if c.isupper() else d[x]["lower"].append(c)
    return d


time_with_comp = timeit.repeat(
    stmt="d = with_comp(given_list)", setup="from __main__ import given_list, with_comp"
)
time_with_defaultdict = timeit.repeat(
    stmt="d = with_defaultdict(given_list)",
    setup="from __main__ import given_list, with_defaultdict",
)
time_plain = timeit.repeat(
    stmt="d = plain(given_list)",
    setup="from __main__ import given_list, plain",
)

print("with_comp: {:.2f}".format(fmean(time_with_comp)))
print("with_defaultdict: {:.2f}".format(fmean(time_with_defaultdict)))
print("plain: {:.2f}".format(fmean(time_plain)))

which gives times:

with_comp: 3.91
with_defaultdict: 4.85
plain: 3.50

I'm sure there is an even better way.

  • Related