Python Dictionary - List Nesting - python

I have a dictionary with a key and a pair of values, the values are stored in a List. But i'm keeping the list empty so i can .append its values ,i cant seem to be able to do this
>>>myDict = {'Numbers':[]}
>>>myDict['Numbers'[1].append(user_inputs)
doesn't seem to work, returns an error . How do i refer to the list in myDict so i can append its values.
Also is it possible to have a dictionary inside a list and also have another list inside? if so? what is its syntax or can you recommend anyother way i can do this
>>>myDict2 = {'Names': [{'first name':[],'Second name':[]}]}
do i change the second nested list to a tuple?? Please lets keep it to PYTHON 2.7

You get an error because your syntax is wrong. The following appends to the list value for the 'Numbers' key:
myDict['Numbers'].append(user_inputs)
You can nest Python objects arbitrarily; your myDict2 syntax is entirely correct. Only the keys need to be immutable (so a tuple vs. a list), but your keys are all strings:
>>> myDict2 = {'Names': [{'first name':[],'Second name':[]}]}
>>> myDict2['Names']
[{'first name': [], 'Second name': []}]
>>> myDict2['Names'][0]
{'first name': [], 'Second name': []}
>>> myDict2['Names'][0]['first name']
[]

You should access the list with myDict['Numbers']:
>>>myDict['Numbers'].append(user_inputs)
You can have dicts inside of a list.
The only catch is that dictionary keys have to be immutable, so you can't have dicts or lists as keys.

You may want to look into the json library, which supports a mix of nested dictionaries and lists.
In addition, you may also be interested in the setdefault method of the dictionary class.
Format is something like:
new_dict = dict()
some_list = ['1', '2', '3', ...]
for idx, val in enumerate(some_list):
something = get_something(idx)
new_dict.setdefault(val, []).append(something)

Related

Update the first value of a dictionary

I have a list of multiple dictionaries.
The structure of my dictionaries are like that :
{'word': 'hello world', 'definition': 'saying hello to the world'}
I would like to update only the first value, so here 'hello world' in order to have it in upper case.
Here is my comprehension list i'm trying with:
upper = {key: value.upper()[0] for key, value in words_dict.items()}
The problem is that with this I have this result:
{'word': 'H', 'definition': 'S'}
I've tried loads of things but I'm still blocked...
A list comprehension is not very useful if all you want is to change the first item of the dict. You can change the dict in-place.
One way of doing it, without specifying the key name:
words_dict[next(iter(words_dict))] = words_dict[next(iter(words_dict))].upper()
You could do something like
upper = {key: words_dict[key].upper() if idx==0 else words_dict[key] for idx, key in enumerate(words_dict.keys())}
But using a dictionary comprehension here is hardly very readable. Perhaps a more readable approach would be to copy the dictionary and then just modify the first element.
upper = words_dict.copy()
first = list(upper.keys())[0]
upper[first] = upper[first].upper()
If you want to update the original dictionary, obviously operate on the original instead of on a copy.

Returning a list of dictionaries by iterating over given data

So let's say I've a list of students and there is a dictionary containing some data for each student as given below :
students= [{'student_name': 'name1',
'regNO': '12',
},{'student_name': 'name2',
'regNO': '13',
},{'student_name': 'name3',
'regNO': '14',
}
]
So based on the above data I want to return another list of dictionaries containing data for each student,
I wrote the following code :
res_dict = {}
res_list = []
for student in students:
res_dict['name']=student['student_name']
res_list.append(res_dict)
print(res_list)
I was hoping that in the output, for each student , there would be a dictionary with key being 'name' and value being the student name taken from 'students' list. I expected it to be as follows :
[{'name': 'name1'}, {'name': 'name2'}, {'name': 'name3'}]
But the output turned out to be this :
[{'name': 'name3'}, {'name': 'name3'}, {'name': 'name3'}]
Can anyone help me identify the issue in my code ?
The better way to get the desired result is via using list comprehension expression as:
[{'name': student['student_name']} for student in students]
The issue with your code is you are updating the values in same reference of the dict object and appending the same object again to the list. Change your code to:
for student in students:
res_dict = {} # Create new `dict` object
res_dict['name'] = student['student_name']
res_list.append(res_dict)
OR, you may just do:
for student in students:
res_list.append({'name': student['student_name']})
The subtle concept of list is that it does not copy the item that you append to it.Instead of that it just stores the pointer to the newly added object via append,similar to pointer arrays in c.So when you try print(res_dict),it will give you the the result like this [{'name': 'name3'}, {'name': 'name3'}, {'name': 'name3'}].But when you append this to the list,all the items in the list point to the same object.You can verify this by this small fragment of code
for i in res_list:
print(id(i))
You will find the same memory address for all the list elements.
But when you take a copy of the dictionary with the help of d.copy() and append that to the res_list,you can see that all the list objects are pointing to different objects by the same technique using id(i) and for loop as shown above.
So finally the corrected code would be
students= [{'student_name': 'name1',
'regNO': '12',
},{'student_name': 'name2',
'regNO': '13',
},{'student_name': 'name3',
'regNO': '14',
}
]
res_dict = {}
res_list = []
for student in students:
res_dict['name']=student['student_name']
res_list.append(res_dict.copy())
print(res_list)
Using list comprehension would always expose the contents to be modified.
This is a classic reference issue. In other words you are appending the reference to the same dict object. Thus, when you change the name value on it, for all times it shows up in the list it will reflect its new value. Instead, create a new dict for each iteration and append that :)
Here is a simple way to do it.
n_list = [{'name':i['student_name']} for i in students]
You should reset res_dict = {} to an empty dict within your loop for each new entry.

Unpacking a tuple with dictionaries in Python

I have a tuple with multiple dictionaries and I wish to unpack them for further use.
Let's say I have this:
tuple_to_add = {'name': 'custom1', 'value': 'first value'},{'name': 'custom2', 'value': 'second value'}
And I'd like to iterate through them
I tried something like that but it didn't give me my answer:
for value, name in tuple_to_add:
print(value)
print(name)
Dictionaries can't be unpacked in a way tuples and lists can. If you had a tuple of tuples, your way of printing would work just fine:
tuple_to_add = ('custom1', 'first value'), ('custom2', 'second value')
for name, value in tuple_to_add:
# do whatever you want
You can simply iterate over the tuple and get the actual dictionary objects which you can use to get all the necessary information:
for dc in tuple_to_add:
print(dc['value'])
print(dc['name'])

How do I turn list values into an array with an index that matches the other dic values?

Hoping someone can help me out. I've spent the past couple hours trying to solve this, and fair warning, I'm still fairly new to python.
This is a repost of a question I recently deleted. I've misinterpreted my code in the last example.The correct example is:
I have a dictionary, with a list that looks similar to:
dic = [
{
'name': 'john',
'items': ['pants_1', 'shirt_2','socks_3']
},
{
'name': 'bob',
items: ['jacket_1', 'hat_1']
}
]
I'm using .append for both 'name', and 'items', which adds the dic values into two new lists:
for x in dic:
dic_name.append(dic['name'])
dic_items.append(dic['items'])
I need to split the item value using '_' as the delimiter, so I've also split the values by doing:
name, items = [i if i is None else i.split('_')[0] for i in dic_name],
[if i is None else i.split('_')[0] for i in chain(*dic_items)])
None is used in case there is no value. This provides me with a new list for name, items, with the delimiter used. Disregard the fact that I used '_' split for names in this example.
When I use this, the index for name, and item no longer match. Do i need to create the listed items in an array to match the name index, and if so, how?
Ideally, I want name[0] (which is john), to also match items[0] (as an array of the items in the list, so pants, shirt, socks). This way when I refer to index 0 for name, it also grabs all the values for items as index 0. The same thing regarding the index used for bob [1], which should match his items with the same index.
#avinash-raj, thanks for your patience, as I've had to update my question to reflect more closely to the code I'm working with.
I'm reading a little bit between the lines but are you trying to just collapse the list and get rid of the field names, e.g.:
>>> dic = [{'name': 'john', 'items':['pants_1','shirt_2','socks_3']},
{'name': 'bob', 'items':['jacket_1','hat_1']}]
>>> data = {d['name']: dict(i.split('_') for i in d['items']) for d in dic}
>>> data
{'bob': {'hat': '1', 'jacket': '1'},
'john': {'pants': '1', 'shirt': '2', 'socks': '3'}}
Now the data is directly related vs. indirectly related via a common index into 2 lists. If you want the dictionary split out you can always
>>> dic_name, dic_items = zip(*data.items())
>>> dic_name
('bob', 'john')
>>> dic_items
({'hat': '1', 'jacket': '1'}, {'pants': '1', 'shirt': '2', 'socks': '3'})
You need a list of dictionaries because the duplicate keys name and items are overwritten:
items = [[i.split('_')[0] for i in d['items']] for d in your_list]
names = [d['name'] for d in your_list] # then grab names from list
Alternatively, you can do this in one line with the built-in zip method and generators, like so:
names, items = zip(*((i['name'], [j.split('_')[0] for j in i['items']]) for i in dic))
From Looping Techniques in the Tutorial.
for name, items in div.items():
names.append(name)
items.append(item)
That will work if your dict is structured
{'name':[item1]}
In the loop body of
for x in dic:
dic_name.append(dic['name'])
dic_items.append(dic['items'])
you'll probably want to access x (to which the items in dic will be assigned in turn) rather than dic.

Sorting list of dictionaries according to a certain key

runnerList = [{1:{"name":"John","height":173,"age":16}},
{2:{"name":"Fred","height":185,"age":18}},
{3:{"name":"Luke","height":181,"age":17}}]
I've been trying to sort this list of dictionaries in ascending order according to the age of the runners, with no success :( I tried:
import operator
runnerList.sort(key=lambda x: x['age'], reverse=True)
But nothing seemed to happen. How would i do this?
Try this:
runnerList.sort(key=lambda x: x.values()[0]['age'])
print runnerList
The reason you were getting an error is that your relevant dictionaries (those containing the age key) were also contained inside another dictionary. The solution was just as simple getting the values() of that external dict and getting grabbing the first element ([0]) which gave you the only dictionary contained inside.
Also, I removed the reverse=True used in your example. It would have given you the results in descending order and you specifically asked for them to be in ascending order.
Disclaimer:
If you're using a Python version >= 3:, you'd have to convert the generator object created with values().
runnerList.sort(key=lambda x: list(x.values())[0]['age'])
runnerList is list of dictionaries of dictionaries.
if you are sure that each list entry has only one pair of key-value, then you can sort by:
runnerList.sort(key=lambda x: list(x.values())[0]['age'], reverse=True)
if each list entry has more then one key-value pair, then you need to specify better the logic of your sort. what would you do on list like this?:
runnerList = [{1:{"name":"John","height":173,"age":16}},
{ 2:{"name":"Fred","height":185,"age":18},
4:{"name":"Fred","height":185,"age":13}
},
{3:{"name":"Luke","height":181,"age":17}}]
You basically have the runnerList in form of list as it is enclosed in []. First change it to dictionary like
runnerList = {1:{"name":"John","height":173,"age":16},
2:{"name":"Fred","height":185,"age":18},
3:{"name":"Luke","height":181,"age":17} }
and then you can import operator and can use the below function to sort the items and print it
sorted_runnerList = sorted(runnerList.items(),key=lambda x: x[1]['age'],)
While this would directly sort the age in the dictionary within the dictionary
So basically your function becomes
import operator
runnerList = {1:{"name":"John","height":173,"age":16},
2:{"name":"Fred","height":185,"age":18},
3:{"name":"Luke","height":181,"age":17} }
sorted_runnerList = sorted(runnerList.items(),key=lambda x: x[1]['age'],)
print sorted_runnerList
But do remember as we are using the .items() it would return immutable tuples
Output
[(1, {'age': 16, 'name': 'John', 'height': 173}), (3, {'age': 17, 'name': 'Luke', 'height': 181}), (2, {'age': 18, 'name
': 'Fred', 'height': 185})]

Categories

Resources