1

I have a list of values, and a dictionary of dictionaries. They look something like this:

d = {1 : {1 : '', 2 : '', 3 : ''},2 : {1 : '', 2 : '', 3 : ''}}
l = ['Erich Martin', 'Zia Michael', 'Olga Williams', 'Uma Gates']

I am trying to map the values from the list into the dictionary, filling each dictionary before moving on to the next nested dictionary. The last dictionary would have some empty slots, and that's fine. I can't seem to wrap my head around what I need to do; I run into the end of the list and get a keyerror, as there are no more values. Here's the gist of what I've got so far:

for g,s in d.items():
        for i in s:
                s[i] = l.pop()

Using Python 3.4.

Thanks!

3
  • 1
    What does it meap to map the values from the list into the dict? can you provide an example of what you would like to get? Commented Nov 6, 2014 at 20:16
  • 1
    It looks like you really want to chop up your list of names. You can try this: [l[i:i+3] for i in range(0, len(l), 3)]. This will create a list with items grouped 3 at a time. Commented Nov 6, 2014 at 20:19
  • you know, that a dictionary no order. Commented Nov 6, 2014 at 20:21

4 Answers 4

1

Try this:

edited based on ikaros45's comment

for g,s in d.items():
    for i in s:
        if not l:
            break
        s[i] = l.pop()

This will yield:

{1: {1: 'Uma Gates', 2: 'Olga Williams', 3: 'Zia Michael'}, 2: {1: 'Erich Martin', 2: '', 3: ''}}
Sign up to request clarification or add additional context in comments.

3 Comments

That did it; I had tried some while len(l) > 0: without success. this makes more sense and is cleaner.
In python there is no need to check for length of a list. Just do if not l: break
You're right, @ikaros45. I've updated my answer with your suggestion.
0

You are modifying the dictionary as you iterate over it. Fix that first:

for g,s in d.items():
    for i in list(s):
        s[i] = l.pop()

You also need to stop when the list is empty:

try:
    for g,s in d.items():
        for i in list(s):
            s[i] = l.pop()
except IndexError:
    pass
else:
    if l:
        # There weren't enough slots, handle it or raise an exception

Comments

0

I assume you want to put the names into the dict values, replacing the empty string. In that case, I would dump your initial dictionaries and do it this way:

from itertools import count

def generate(lst):
    target = {}
    for index in count(1):
        target[index] = {}
        for subindex in xrange(1, 4):
            target[index][subindex] = lst.pop()
            if not lst:
                return target

generate(['Erich Martin', 'Zia Michael', 'Olga Williams', 'Uma Gates'])

or more elegantly

from itertools import izip_longest

def generate(lst):
    groups = izip_longest(fillvalue='', *([iter(lst)] * 3))
    dictgroups = [dict(enumerate(group, 1)) for group in groups]
    return dict(enumerate(dictgroups, 1))

generate(['Erich Martin', 'Zia Michael', 'Olga Williams', 'Uma Gates'])

Both solutions would work with any input list, no restriction on length as you would have with the approach of mutating an existing dict.

Comments

0

A different approach so as to deal with the inherent unsorted nature of a dict. Also, popping from the list seems to give the values in reverse order and destroys the original list (which may be ok if you have no further use for it), so I have used iter to iterate through the list as required.

d = {1 : {1 : '', 2 : '', 3 : ''},2 : {1 : '', 2 : '', 3 : ''}}
l = ['Erich Martin', 'Zia Michael', 'Olga Williams', 'Uma Gates']

i = iter(l)

for outer in sorted(d.keys()):
    for inner in sorted(d[outer].keys()):
        try:
            d[outer][inner]=next(i)
        except StopIteration:
            break

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.