3

I am new to Python, and trying to learn it "on the job". And I am required to do this.

Is it possible to create a 'dictionary1' dynamically which takes another 'dictionary2' as value, where 'dictionary2' is also getting updated in every for loop. Basically in terms of code, I tried:

fetch_value = range(5) #random list of values (not in sequence)

result = {} #dictionary2
ret = {} #dictionary1

list1 = [0, 1] #this list is actually variable length, ranging from 1 to 10 (assumed len(list1) = 2 for example purpose only)

for idx in list1:
    result[str(idx)] = float(fetch_value[1])
    ret['key1'] = (result if len(list1) > 1 else float(fetch_value[1])) # key names like 'key1' are just for representations, actual names vary
    result[str(idx)] = float(fetch_value[2])
    ret['key2'] = (result if len(list1) > 1 else float(fetch_value[2]))
    result[str(idx)] = float(fetch_value[3])
    ret['key3'] = (result if len(list1) > 1 else float(fetch_value[3]))
    result[str(idx)] = float(fetch_value[4])
    ret['key4'] = (result if len(list1) > 1 else float(fetch_value[4]))

print ret

This outputs to:

{'key1': {'0': 4, '1', 4}, 'key2': {'0': 4, '1', 4}, 'key3': {'0': 4, '1', 4}, 'key4': {'0': 4, '1', 4}}

What I need:

{'key1': {'0': 1, '1', 1}, 'key2': {'0': 2, '1', 2}, 'key3': {'0': 3, '1', 3}, 'key4': {'0': 4, '1', 4}}

anything obvious I am doing wrong here?

eecs
  • 141
  • 2
  • 13
  • 2
    You need to use copies of the inner dictionary via `result.copy()` – Moses Koledoye Aug 26 '16 at 20:27
  • 1
    You probably want to use a dictionary comprehension that creates new inner dictionaries as needed instead of copying one dictionary repeatedly, e.g. `{key: {idx: fetch_value(idx) for idx in [0, 1]} for key in range(1, 5)}`. – Sven Marnach Aug 26 '16 at 20:38
  • @MosesKoledoye Thanks! That is useful, but now by replacing result to result.copy() in the code above, the output is `{'key1': {'0': 4, '1', 1}, 'key2': {'0': 4, '1', 2}, 'key3': {'0': 4, '1', 3}, 'key4': {'0': 4, '1', 4}}` – eecs Aug 26 '16 at 20:47
  • so you are doing a couple things that are weird. your (result if len(list1) > 1 else float(fetch_value[1])) will always evaluate to true right? the len(list1) isn't going to change – bravosierra99 Aug 26 '16 at 20:50
  • perhaps you wanted to use for i,idx in enumerate(list1) – bravosierra99 Aug 26 '16 at 20:51

1 Answers1

2

There are two problems:

  1. You needed to create a copy of the result dictionary when you set a key in ret to it. Otherwise, it will always hold a reference back to the same dictionary.
  2. With that change, you would be keeping the last ret dictionary (containing {'0': 4}) at the beginning of your second loop, and that would get copied to all of the keys.

A more concise way to do this would be a dictionary comprehension:

fetch_value = range(5)
list1 = [0, 1]
print {
    'key{}'.format(i): {
        str(list_item): float(fetch_value[i]) for list_item in list1
    } if len(list1) > 1 else float(fetch_value[i])
    for i in xrange(1, 5)
}

Output:

{
    'key3': {'1': 3.0, '0': 3.0},
    'key2': {'1': 2.0, '0': 2.0},
    'key1': {'1': 1.0, '0': 1.0},
    'key4': {'1': 4.0, '0': 4.0}
}

And with list1 = [0], where it seems you want a float value instead of a dictionary, the output would be:

{'key3': 3.0, 'key2': 2.0, 'key1': 1.0, 'key4': 4.0}
Karin
  • 8,404
  • 25
  • 34