python: search in list of lists of dictionaries - python

I want to iterate over a list of lists of dictionaries:
data = [
{'name': 'sravan'},
{'name': 'bobby'},
{'name': 'ojsawi', 'number': '123'},
{'name': 'rohith', 'number': '456'},
{'name': 'gnanesh', 'number': '123'}
]
Furthermore I want to check each entry if there is a key number where the value is 123.
If so, I want to append the value of name of this entry in a new list
which would be 'ojsawi' and 'gnanesh' in the above case.
Else, I want to append 0 in the new list.
This means, the final new_list with the appended values should look like this:
new_list = {0, 0, 'ojsawi', 0, 'gnanesh'}
I have tried different versions/possibillities with 2D for loops and lambdas etc. but I think the main problem is that the lists have different sizes. Any help/tipps would be much appreciated.

You can define it with list comprehensions with a nested if/else in it:
new_list = [x.get('name') if x.get('number') == '123' else 0 for x in data]
Outputting:
[0, 0, 'ojsawi', 0, 'gnanesh']

Other than list comprehensions, you can also do it using map() and functional programming if you want. Note that map() returns an iterator which generates things as you go if you are using a for loop, so if you want the entire result immediately, use list() around your map() function.
def zerofilter(my_dict):
number = my_dict.get("number")
if number != "123":
return 0
else:
return my_dict.get("name")
data = [
{'name': 'sravan'},
{'name': 'bobby'},
{'name': 'ojsawi', 'number': '123'},
{'name': 'rohith', 'number': '456'},
{'name': 'gnanesh', 'number': '123'}
]
print(list(map(zerofilter, data))) # output is [0, 0, 'ojsawi', 0, 'gnanesh']
# You can also do this:
for res in map(zerofilter, data):
print(res)

Related

python, map name from a list to a list of dict

I have the following list and list of dicts:
data = [dict(position=1, value=150.3),
dict(position=0, value=28.5),
dict(position=2, value=1050.3)]
names = ["CL", "ES", "EUR"]
I would like to map the values of the list into the list of dicts so they match the value stated in the key "position" of the dict - to get the following result:
data = [dict(name="ES", position=1, value=150.3),
dict(name="CL", position=0, value=28.5),
dict(name="EUR", position=2, value=1050.3)]
Is there any "smart" and pythonic way to achieve that?
First of all, please present your question in actual Python form. dict is a type; the way you represent dictionaries in Python is with {}.
Also, you don't have "a dict and list", you have two lists, one of which consists of three dictionaries. So:
data = [
{'position': 1, 'value': 150.3},
{'position': 0, 'value': 28.5},
{'position': 2, 'value': 1050.3}
]
names = ["CL", "ES", "EUR"]
So, given that you do have lists, there is no concern about ordering. A simple loop will give you what you want:
for d in data:
d['name'] = names[d['position']]
This updates data in place:
>>> data
[{'position': 1, 'name': 'ES', 'value': 150.3}, {'position': 0, 'name': 'CL', 'value': 28.5}, {'position': 2, 'name': 'EUR', 'value': 1050.3}]
You can use a list comprehension and dictionary update:
data = [dict(position = 2, value=150.3),
dict(position = 1, value = 28.5),
dict(position=3, value=1050.3)]
names = ['CL', 'ES', 'EUR']
# Sort names according to "position" value of the dictionary
sorted_names = [names[idx] for idx in map(lambda x: x['position'], data)]
# Update modifies inplace
_ = [data[idx].update({'name' : el}) for idx, el in enumerate(sorted_names)]
Which gives the expected output:
data
[{'name': 'ES', 'position': 2, 'value': 150.3},
{'name': 'CL', 'position': 1, 'value': 28.5},
{'name': 'EUR', 'position': 3, 'value': 1050.3}]
You could try:
data = [{"position": 2, "value": 150},
{"position": 1, "value": 200}]
names = ["CL", "ES"]
for item in data:
item["name"] = names[item["pos"] - 1]
Where we go through all the dictionaries in the list, then for each dictionary we set the "name" key to be equal to the value in data at the position described in item["pos"] minus 1.
This of course assumes your data is clean and all items in data correctly map to items in names.
If this is not the case, use a try-except:
for item in data:
try:
item["name"] = names[item["pos"] - 1]
except IndexError:
item["name"] = None
You can also use the update method on the dictionary elements in the list, if you like the keyword-argument convention, as the style of your question suggests.
for item in data:
item.update(name=names[item["position"]])
A one liner implementation using list comprehension.
print [dict(d.items()+[('name',names[d['position']-1])]) for d in data]

Python: remove dictionary from list, given list of keys to remove

I have an extension question to remove dictionary from list, except that I have a list of dictionary keys I would like to remove from the list.
So, I have something like:
a=[{'id': 1, 'name': 'paul'},{'id': 2, 'name': 'john'},{'id': 3, 'name': 'john2'},{'id': 4, 'name': 'johnasc'}]
now, I have a del_list, like so:
del_id_list=[2,4]
what is the efficient way (assuming list a is LARGE) to delete dictionaries with id from del_list from a?
one way, recreating the list using a list comprehension (and declaring del_id_list as a set for faster lookup):
a=[{'id': 1, 'name': 'paul'},{'id': 2, 'name': 'john'},{'id': 3, 'name': 'john2'},{'id': 4, 'name': 'johnasc'}]
del_id_list={2,4}
new_a = [d for d in a if d['id'] not in del_id_list]
result:
[{'id': 1, 'name': 'paul'}, {'id': 3, 'name': 'john2'}]
Get acquainted with filter:
result = filter(lambda x: x['id'] not in del_id_list,a)
EDIT:
Regarding the del_id_list itself, if it's long you may want to consider the complexity of the in statement. Maybe a set and even a dict (with arbitrary value) would be better. Check this.
EDIT 2:
As #Jean correctly points out, this is a iteration sequence in Py3. Just add list:
result = list(filter(lambda x: x['id'] not in del_id_list,a))
sourceList = [{'id': 1, 'name': 'paul'},{'id': 2, 'name': 'john'},{'id': 3, 'name': 'john2'},{'id': 4, 'name': 'johnasc'}]
del_id_list = [2,4]
for itemDict in sourceList:
if itemDict['id'] in del_id_list:
sourceList.remove(itemDict)
print(sourceList)
Result -> [{'name': 'paul', 'id': 1}, {'name': 'john2', 'id': 3}]

Split python list in filtered list of multiple list and store them in single list

I have an exhaustive list of different categories with me:
myList = [
{'name': 'Sasha', 'category': 'Dog'},
{'name': 'Meow', 'category': 'Cat'},
{'name': 'Bark', 'category': 'Dog'}
]
I want them to break and a create smaller list within this bigList. It would be similar to this:
bigList = [
[
{'category': 'Dog', 'name': 'Sasha'},
{'category': 'Dog', 'name': 'Bark'}
],
[
{'category': 'Cat', 'name': 'Meow'}
]
]
Here is the python logic for iterating the loop:
bigList = []
prev = ''
for s in myList:
newList = []
if s['category'] != prev:
for m in myList:
if m['category'] == s['category']:
newList.append(m)
bigList.append(newList)
prev = s['category']
This has done the trick for me but I would like to know how can I optimize the above logic in for loop for more shorter and efficient code.
You can do this in two steps with groupby as commented by #roganjosh:
from itertools import groupby
# step 1: sort the list by category, we need this step because groupby only groups same
# adjacent values so we need to sort the list so that same category are close to each other
sort_list = sorted(myList, key = lambda x: x["category"])
# step 2: group by the category and create a new sub list for each group
[list(g) for _, g in groupby(sort_list, key = lambda x: x['category'])]
#[[{'category': 'Cat', 'name': 'Meow'}],
# [{'category': 'Dog', 'name': 'Sasha'}, {'category': 'Dog', 'name': 'Bark'}]]
Sorting can be expensive for large lists.
Starting with your data:
my_list = [
{'name': 'Sasha', 'category': 'Dog'},
{'name': 'Meow', 'category': 'Cat'},
{'name': 'Bark', 'category': 'Dog'}
]
This loops through all elements of your list once and rembers what its has already seen before in a dictionary:
res = []
seen = {}
for entry in my_list:
val = seen.setdefault(entry['category'], [])
if not val:
res.append(val)
val.append(entry)
It appends a new list only for not yet seen entries to res but all entries to the corresponding nested list val that it got from the seen dictionary. So, the same val is in res and in seen. Hence, appending to val will enlarge val and the effect can be seen no matter if your access val through res and or seen. The line val = seen.setdefault(entry['category'], []) gives you either an existing list, if the category was seen before or, a new empty list if the category was encountered the first time. At the same time, if the category is not yet in seen, it adds a new key with an empty list as value to seen.
This is the result:
import pprint
pprint.pprint(res)
[[{'category': 'Dog', 'name': 'Sasha'}, {'category': 'Dog', 'name': 'Bark'}],
[{'category': 'Cat', 'name': 'Meow'}]]

generate list from values of certain field in list of objects

How would I generate a list of values of a certain field of objects in a list?
Given the list of objects:
[ {name: "Joe", group: 1}, {name: "Kirk", group: 2}, {name: "Bob", group: 1}]
I want to generate list of the name field values:
["Joe", "Kirk", "Bob"]
The built-in filter() function seems to come close, but it will return the entire objects themselves.
I'd like a clean, one line solution such as:
filterLikeFunc(function(obj){return obj.name}, mylist)
Sorry, I know that's c syntax.
Just replace filter built-in function with map built-in function.
And use get function which will not give you key error in the absence of that particular key to get value for name key.
data = [{'name': "Joe", 'group': 1}, {'name': "Kirk", 'group': 2}, {'name': "Bob", 'group': 1}]
print map(lambda x: x.get('name'), data)
In Python 3.x
print(list(map(lambda x: x.get('name'), data)))
Results:
['Joe', 'Kirk', 'Bob']
Using List Comprehension:
print [each.get('name') for each in data]
Using a list comprehension approach you get:
objects = [{'group': 1, 'name': 'Joe'}, {'group': 2, 'name': 'Kirk'}, {'group': 1, 'name': 'Bob'}]
names = [i["name"] for i in objects]
For a good intro to list comprehensions, see https://docs.python.org/2/tutorial/datastructures.html
Just iterate over your list of dicts and pick out the name value and put them in a list.
x = [ {'name': "Joe", 'group': 1}, {'name': "Kirk", 'group': 2}, {'name': "Bob", 'group': 1}]
y = [y['name'] for y in x]
print(y)

Adding a key value pair to a list of dicts based on another list Python

Sorry if the title is not clear, but here is what I'm trying to achieve.
I have a list of dicts :
l = [{'name': 'inAnalysis'}, {'name': 'inQuest'}, {'name': 'inDevelopment'}]
And a sort of translation table like this :
tr = {'inAnalysis' : 1, 'inDevelopment' : 2, 'inQuest' : 3}
I want to add the key value to l like this :
l = [{'name': 'inAnalysis', 'order' : 1},
{'name': 'inQuest', 'order' : 3},
{'name': 'inDevelopment', 'order' : 2}]
How can I match the value of l with the key of tr and get its value with the key order and add it to l? Any help would be appreciated. I'm using Python 2.6.
You can use list comprehension to dynamically generate the dictionaries like this
print [{"name":dic["name"], "order":tr[dic["name"]]} for dic in l]
Output
[{'name': 'inAnalysis', 'order': 1},
{'name': 'inQuest', 'order': 3},
{'name': 'inDevelopment', 'order': 2}]
Alternatively, you can use the following
for dic in l: dic["order"] = tr[dic["name"]]
this modifies the dictionaries in-place.
If you want to modify the existing dictionaries in place (note that thefoutheye's solution makes new dictionaries which could concievably be a problem if something else in your code is holding a reference to the dictionaries in the list, rather than the list itself) you can do:
for my_dict in l:
my_dict['order'] = tr[my_dict['name']]

Categories