简体   繁体   中英

Creating a dict containing a sub-dict as the new value with the index as the key

I have a dictionary currently setup as

{'name': 'firm', 'name':'firm', etc}, 

Where keys are analyst names and values are analyst firms.

I am trying to create a new dictionary where the new values are the old k,v pairs and the associated key is simply the index (1, 2, 3, 4, etc) .

Current code is below:

num_analysts = len(analysts.keys())
for k,v in analysts.items():
    analysts_dict = dict.fromkeys(range(num_analysts), [k,v])

Current result

Each numeric key is getting given the same value (old k,v pair) . What is wrong with my expression?

You can enumerate the items and convert them to a dictionary. However, dictionaries, in general, are not ordered. This means that the keys may be assigned essentially randomly.

dict(enumerate(analysts.items(), 1))
#{1: ('name1', 'firm1'), 2: ('name2', 'firm2')}

Enumerate and dictionary comprehension for this

d = {'name1': 'firm1', 'name2': 'firm2'}
d2 = {idx: '{}, {}'.format(item, d[item]) for idx, item in enumerate(d, start = 1)}
 {1: 'name1, firm1', 2: 'name2, firm2'} 

There are already effective answer posted by others. So I may just put the reason why your own solution does't work properly. It may caused by lazy binding. There are good resource on: http://quickinsights.io/python/python-closures-and-late-binding/

Because late binding will literally pick up the last one in dictionary you created. But this last one is not "virtually last one", it is determined by the OS. (Other people already give some explanation on dict data-structure.)

For each time you run in python command line the result may change. If you put the code in .py file, For each time you run in IDE, the result will be same.(always the last one in dict)

During each iteration, analysts_dict is assigned value based on the result of dict.items(). However, you should use comprehension to generate the final result in one line,

Eg [{i: e} for i, e in enumerate(analysts.items())]

analysts = {
    "a": 13,
    "b": 123,
    "c": 1234
}
num_analysts = len(analysts.keys())
analysts_dict = [{i: e} for i, e in enumerate(analysts.items())]
print(analysts_dict)

>> [{0: ('a', 13)}, {1: ('b', 123)}, {2: ('c', 1234)}]

This code

for k,v in analysts.items(): 
    analysts_dict = dict.fromkeys(range(num_analysts), [k,v])

loops over the original dict and on each loop iteration it creates a new dict using the range numbers as the keys. By the way, every item in that dict shares a reference to a single [k, v] list object. That's generally a bad idea. You should only use an immutable object (eg None , a number, or a string) as the value arg to the dict.fromkeys method. The purpose of the method is to allow you to create a dict with a simple default value for the keys you supply, you can't use it to make a dict with lists as the values if you want those lists to be separate lists.

The new dict object is bound to the name analysts_dict . On the next loop iteration, a new dict is created and bound to that name, replacing the one just created on the previous loop, and the replaced dict is destroyed.

So you end up with an analysts_dict containing a bunch of references to the final [k, v] pair read from the original dict.

To get your desired result, you should use DYZ's code, which I won't repeat here. Note that it stores the old name & firm info in tuples, which is better than using lists for this application.

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