Creating a list of dictionaries with same keys? [duplicate] - python

This question already has answers here:
Creating a list of dictionaries results in a list of copies of the same dictionary
(4 answers)
Closed 1 year ago.
I wanted to create a list that contains x amount of dictionaries all containing the same keys but with different values that's made in a for loop:
Something like
[{'name': Brenda, 'Age': 22, 'Sex': Female},
{'name': Jorda, 'Age': 32, 'Sex': Male},
{'name': Richard, 'Age': 54, 'Sex': Male}]
My code is this:
people = []
person = {}
humans = gethumans()
for human in humans:
number_people, people_data = People.data()
person['name'] = human.name
person['age'] = human.age
person['Sex'] = human.name
people.append(person)
My output is something like this:
[{'name': Richard, 'Age': 54, 'Sex': Male},
{'name': Richard, 'Age': 54, 'Sex': Male}
{'name': Richard, 'Age': 54, 'Sex': Male}]
Since the dictionary values are getting replaced and not added and it's just appending the same dictionary. How can I get around this?

When you append the dictionary person to the list people you are just appending a reference to the dictionary to the list, so the list ends up containing just references to the SAME dictionary.
Since each time through the loop you overwrite the dictionary with new values, at the end the list contains just references to the last person you appended.
What you need to do is create a new dictionary for every person, for example:
for human in humans:
number_people, people_data = People.data()
person = dict()
person['name'] = human.name
person['age'] = human.age
person['Sex'] = human.name
people.append(person)

You each time edit the same dictionary, so you do not construct a new one, but edit the old one. Since you each time append the same dictionary to the list, in the end the list contains the same dictionary n times, and all edits are processed on that dictionary.
You thus have to construct a new dictionary in each iteration in the for loop:
people = []
humans = gethumans()
for human in humans:
number_people, people_data = People.data()
person = {
'name': human.name,
'age': human.age,
'sex': human.sex
}
people.append(person)
I here replaced 'Sex' with 'sex' (since it is strange to have inconsistent key names), and used human.sex instead of human.name.
Here people.data() do not seem to do anything, you can thus use list comprehension here to generate the list:
people = [
{ 'name': human.name, 'age': human.age, 'sex': human.sex }
for human in humans
]
This will construct a list with all the dictionaries. Given the for loop had no side-effects (this looks to be the case), the above will work.

Related

Python Accessing a Value in a List of Dictionaries, if another Value in the Dictionary Exists

My question is an extension to this:
Python Accessing Values in A List of Dictionaries
I want to only return values from dictionaries if another given value exists in that dictionary.
In the case of the example given in the linked question, say I only want to return 'Name' values if the 'Age' value in the dictionary is '17'.
This should output
'Suzy'
only.
result = [d["Name"] for d in dicts if d.get("Age") == 17)]
Of course this would select all nanes that satisfy the condition. You can put that in a function.
In the following case :
listname= [
{'Name': 'Albert' , 'Age': 16},
{'Name': 'Suzy', 'Age': 17},
{'Name': 'Johnny', 'Age': 13}
]
If you want return only people Name when "age == 17" use :
for d in listname:
if d['Age'] == 17 :
print (d['Name'])
Use a condition inside your for.
Edit 10/01/2022 : Change "list" to "listname", cause list il already reserved in python.

What is the most pythonic way to copy values from one dictionary into another? [duplicate]

This question already has answers here:
Change the name of a key in dictionary
(23 answers)
Closed 1 year ago.
I would like to know what is the most elegant or pythonic way to copy specific values from one dictionary into another, only if the values are not None, empty, or empty dict.
The new dictionary will have different key names than the original one.
For example, let's assume I got a response from API and I converted json to dict
customer = [{
'name': 'John',
'email': 'johnsmith#gmail.com',
'phoneNumber': '9999999',
'country': 'USA',
'city': None,
'preferences': {}
}]
new_customer_dict = {}
for client in customer:
if client.get('name'):
new_customer_dict ['customer_name'] = client['name']
if client.get('email'):
new_customer_dict['customer_email'] = client['email']
How about something like this:
>>> customer_keys = [k for client in customer for k in client.keys()]
>>> customer_keys
['city', 'name', 'phoneNumber', 'email', 'country', 'preferences']
>>> new_customer_dict = {'customer_{}'.format(k): client.get(k)
... for client in customer
... for k in customer_keys
... if client.get(k) is not None
... and client.get(k)}
>>> new_customer_dict
{'customer_name': 'John', 'customer_phoneNumber': '9999999', 'customer_country': 'USA', 'customer_email': 'johnsmith#gmail.com'}
Basically, first, you make a list of all the keys you want to look for. Next, you iterate over the list while making sure that value (of dict) is not None. You also check if the value (of dict) is not None.
Hope you got the idea!

How to append items from a list into a dictionary?

I'm very new to programming and Python and trying to figure things out. I'm trying to take items out of a list and append the keys and values to a dictionary but I can't figure out how. I tried using the dictionary's Update method but I'm only getting the last item from my list, not all the items. Here is my code:
a = {}
names = [ {'name': 'Bart'}, {'name': 'Lisa'}, {'name': 'Maggie'} ]
for name in names:
a.update(name)
The result I'm getting back is:
{'name': 'Maggie'}
But I want this in my new dictionary:
{'name': 'Bart'}, {'name': 'Lisa'}, {'name': 'Maggie'}
I wanted to put the items from the list inside the dictionary in order to access the values. I need all of the names but maybe there is a much easier way to do it.
Any hints would be great. Thanks.
With same key value you cant update a dict from list of dict. You can get a dict with key a list of values.
{'name': ['Bart', 'Lisa', 'Maggie']}
a={}
for n in names:
... for k in n:
... for k,v in [(k,n[k])]:
... if k not in a:a[k]=[v]
... else: a[k].append(v)

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.

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.

Categories

Resources