Find element in a list of dicts based on value - python

I am trying to find an element in a list, how can I do that? This is what I wrote:
user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
def find_user(user_name):
for items in user_list:
if user_name == 'name':
print(user_name+" exists")
else:
print(user_name+" does not exists")
when I print the following I want it to find the user:
find_user('Alizom_12')

You're close. You need to get the value in the dictionary
if user_name == items['name']:

user_list = [
{'name': 'Alizom_12',
'gender': 'f',
'age': 34,
'active_day': 170},
{'name': 'Xzt4f',
'gender': None,
'age': None,
'active_day': 1152},
{'name': 'TomZ',
'gender': 'm',
'age': 24,
'active_day': 15},
{'name': 'Zxd975',
'gender': None,
'age': 44,
'active_day': 752},
]
def find_user(user_name):
userExists = False
for items in user_list:
for key, value in items.items():
if key == 'name' and value == user_name:
userExists = True
if userExists is True:
print(user_name+" exists")
else:
print(user_name+" does not exists")
find_user('Alizom_12')

There are more than one places that your code has to be fixed:
Let's try to use the code snippet to point out them one by one.
First you can find the user_name by go through each dict. and the key name, secondly, it's better to return and not print.
Lastly, the last print should be out side of the for-loop, otherwise, you will get many repeated not found messages...
def find_user(user_name):
for items in user_list:
if items['name'] == user_name:
return f'{user_name} exists. '
#return items # will return this user's dict. (all info) *You have to comment prev. statement first. and uncomment this
return f'{user_name} - does not exists'
print(find_user('Alizom_12')) # Alizom_12 exists.
print(find_user('John Doe')) # John Doe - does not exists

Related

update values in a list of dictionaries

I have the following list:
list_dict = [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': []}
]
I would like to add a hobby to R2:
for i in range(len(list_dict)):
people = list_dict[i]
if people['name'] == 'R2':
people['hobbies'] = ['lubrication']
print(list_dict)
I got what I was expecting but as a newbie I'd like to learn a few easy tricks to make it shorter.
I'd express as:
people = {person['name']: person for person in list_dict}
people['R2']['hobbies'] += ['lubrication'] # reads nicely as "add a hobby to R2"
For all those hung up on the academic concern of "potential people with same name", although the "Leetcode answer" would be:
for person in list_dict:
if person['name'] == 'R2':
person['hobbies'] += ['lubrication']
But in practice, remodeling data to have & use primary keys is probably what you want in most cases.
You can just iterate over the list and condense the if statement:
for person in list_dict:
person['hobbies'] = ['lubrication'] if person['name'] == 'R2' else person['hobbies']
There are some other answers here but in my eyes they don't really help a newbie seeking to shorten his code. I don't suggest to use the below proposed shortening except the looping over items in list instead of using indices, but to give here an answer with some maybe worth to know 'tricks' (you can have more than one name pointing to same variable/object, you can iterate directly over items of a list instead using indices) to a newbie here a shortened version of the code:
for p in l:
if p[n]=='R2': p[h]=['lubrication']
print(l)
and below all of the code using the proposed shortening with comments pointing out the 'tricks':
list_dict = [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': []},
{'name': 'R2', 'age': 15, 'country': 'Alduin', 'hobbies': []}
]
l = list_dict; n='name'; h='hobbies'
# I would like to add a hobby to R2:
"""
for i in range(len(list_dict)):
people = list_dict[i]
if people['name'] == 'R2':
people['hobbies'] = ['lubrication']
"""
# I got what I was expecting but as a newbie I'd like to learn a few
# easy tricks to make it shorter:
for p in l: # loop over items in list instead of using indices
if p[n]=='R2': p[h]=['lubrication'] # use short variable names
# ^-- give --^ long string constants short names
print(l)
there is no need to loop over the lenght, you can loop through the list and you can condense with a one-liner if statement
#!usr/bin/python3
from pprint import pprint
for person in list_dict:
person['hobbies'].append('lubrification') if person['name'] == 'R2' else ...
pprint(list_dict)
>>> [
{'name': 'Old Ben', 'age': 71, 'country': 'Space', 'hobbies': ['getting wise']},
{'name': 'Han', 'age': 26, 'country': 'Space', 'hobbies': ['shooting']},
{'name': 'Luke', 'age': 24, 'country': 'Space', 'hobbies': ['being arrogant']},
{'name': 'R2', 'age': 'unknown', 'country': 'Space', 'hobbies': ["lubrification"]}
]
you can also do this with a comprehension:
[person['hobbies'].append('lubrification') for person in list_dict if person['name']]
But, if you just want to change one, you can use this code:
m = next(i for i,person in enumerate(list_dict) if person["name"]=="R2")
list_dict[m]["hobbies"].append("lubrification")

Removeing duplicates of a sorted python list while iterting

I Have a sorted data as follows. I want to compare them and remove anything duplicated. Here I do an simple comparison of field to test the code. Original requirement is to some complex comparison. So I need compare the previous with the successor explicitly.
The comparison is not that simple. This is just to show what I am going to achieve. There are several field that need to compare (but NOT all) and remove the previous if same values and keep the newer one which will be having a incremental number. Hence explicit comparison is required. What is the problem in pop() and append() even I don't iterate it?
I used both list and deque. But duplicates are there. Anything wrong with code?
import collections
data = [
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 29},
]
dq = collections.deque()
for i in range(1, len(data)):
prev_name = data[i-1]['name']
prev_age = data[i-1]['age']
next_name = data[i]['name']
next_age = data[i]['age']
dq.append(data[i-1])
if prev_name == next_name and prev_age == next_age:
dq.pop()
dq.append(data[i])
else:
dq.append(data[i])
print(dq)
Output (actual): deque([{'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 29}])
Output (expected): deque([{'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 29}])
The problem with your code is that you are appending the previous data element first, then if the current and previous variables same then you are removing the last element, but the thing you are not considering is that, once you add the current element after removing the previous element in:
dq.pop()
dq.append(data[i])
In the next iteration, you are again adding the previously added element in:
dq.append(data[i-1])
So, if the "if" condition is satisfied then it will just remove the last element (i.e data[i-1]) from dq and not the last element entered in the dq previously. Therefore, here it is getting duplicated with the same element.
You can try this code:
import collections
data = [
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 29},
{'name': 'Atomic', 'age': 29},
{'name': 'Atomic', 'age': 30},
]
dq = collections.deque()
dq.append(data[0])
for i in range(1, len(data)):
prev_name = dq[-1]['name']
prev_age = dq[-1]['age']
next_name = data[i]['name']
next_age = data[i]['age']
if prev_name == next_name and prev_age == next_age:
continue
else:
dq.append(data[i])
print(dq)
Ouput:
deque([{'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 29}, {'name': 'Atomic', 'age': 30}])
You can try this code :
import collections
data = [
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 29},
]
dq = collections.deque()
for i in range(0, len(data)):
if data[i] not in dq:
dq.append(data[i])
print(dq)
output:
deque([{'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 29}])
data = [
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 28},
{'name': 'Atomic', 'age': 29},
]
unique = set((tuple(x.items()) for x in data))
print([dict(x) for x in unique])
[{'name': 'Atomic', 'age': 28}, {'name': 'Atomic', 'age': 29}]

Return can close Loop for? (python/django)

Does return on python close the Loop for?
I'm asking that because I wrote a code that will search for me someone in a list and if know that person it will return me his age if not it will tell me "Person not found".
If the person is in the first place of the Array if find it but if it is in the second he doesn't why?
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
else:
return {'name': 'Person not found', 'age': 0}
def fname(request, name):
result = lerDoBanco(name)
if result['age'] > 0:
return HttpResponse('The person was found, has ' + str(result['age']) + ' years old')
else:
return HttpResponse('Person not found')
I ask that because if I comment the else statement it shows me all the people in the Array correctly.
When you call return operator it will terminate the current function execution and return value. So if you will use return inside your loop, return will terminate the loop and the function and return some value.
return terminates execution further and returns some desired value (default is None). Change indentation to make your code working :
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
return {'name': 'Person not found', 'age': 0}
It will iterate all the values to find the person then if not found then the default value {'name': 'Person not found', 'age': 0} will be returned.
From the moment you return you move out of the function, so out of the for loop as well.
What you thus can do is simply return the 'Person not found' at the end of the function:
def lerDoBanco(name):
lista_names = [
{'name': 'Joaquim', 'age': 20},
{'name': 'João', 'age': 25},
{'name': 'Ana', 'age': 27}
]
for person in lista_names:
if person['name'] == name:
return person
return {'name': 'Person not found', 'age': 0}
Note that if the data is stored in the database, it is better to make a queryset to filter at the database side. Databases are optimized to search effectively. You can also specify db_index=True on a column such that the database builds an index allowing much faster retrieval.
A loop ends when one of the following happens:
loop condition evaluates to false
break is used
an exception is raised
a return statement is executed
The points above are the same for every programming language

Replacing a specific item of a dict in a list of dicts? [duplicate]

This question already has answers here:
Find the index of a dict within a list, by matching the dict's value
(12 answers)
Closed 3 years ago.
Say I have the following list of dicts:
dicts = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5},
... ]
I'd like to replace the age of a given person with a given value.
def replace_age(person, age):
dicts[?]['age'] = age
replace_age("Tom", 45)
Assuming that name is unique, what's the most elegant way to go about this?
In a golden world: dicts[name=person]['age'] = age
Not a duplicate of Find the index of a dict within a list, by matching the dict's value: I'm looking to change the value, not get the index. And Tom is a pretty common name.
this is a variant:
def replace_age(person, age):
try:
dct = next(item for item in dicts if item["name"] == person)
except StopIteration:
# person not found
# here you could print a message or raise an error...
return
dct["age"] = age
this will only work if the names are unique. if they are not only the first occurrence will be replaced.
since the name is unique you can change your data structure where you keep your data to achieve your task efficiently:
efficient_dict = {e['name']: {'age' : e.get('age'), 'height': e.get('height')} for e in dicts}
def replace_age(person, age):
if person in efficient_dict:
efficient_dict[person]['age'] = age
Here's my version
dictionaries = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5}
]
def change_dict_person_age(dictionaries, person, age):
for dictionary in dictionaries:
if dictionary['name'] == person:
dictionary['age'] = age
# Uncomment the following line if you want to stop at the 1st
# match. Leave it as is if you want to modify all occurrences.
#break
change_dict_person_age(dictionaries, "Tom", 40)
print(dictionaries)
#[{'name': 'Tom', 'age': 40, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]
I also wrote a more generic version for broader user:
dictionaries = [
{'name': "Tom", 'age': 20, 'height': 1.8},
{'name': "Isa", 'age': 31, 'height': 1.5}
]
def change_dict(dictionaries, key_to_check, value_to_match, key_to_change, value_to_change):
for dictionary in dictionaries:
if dictionary[key_to_check] == value_to_match:
dictionary[key_to_change] = value_to_change
# Uncomment the following line if you want to stop at the 1st
# match. Leave it as is if you want to modify all occurrences.
#break
change_dict(dictionaries, "name", "Tom", "age", 50)
print(dictionaries)
#[{'name': 'Tom', 'age': 50, 'height': 1.8}, {'name': 'Isa', 'age': 31, 'height': 1.5}]

Multiple For loops, print else only once if condition is not met

There is a loop in a loop, if condition is met some code runs. However, if condition is not met, I need it to print something. Though if I add code to any location, it is printed multiple times. How to make it print only once, if condition is not met?
some_list = {'a_list': [{'name': 'Tom', 'age': 25}, {'name': 'John', 'age': 25}, {'name': 'Val', 'age': 25}], 'b_list': [{'name': 'Don', 'age': 25}, {'name': 'Tim', 'age': 25}, {'name': 'San', 'age': 25}]}
findperson = 'San'
for i in some_list:
for y in some_list[i]:
if y['name'].lower() == findperson.lower():
print('Friend found')
break
else:
print('Friend not found')
You could use any for the inner loop (and break from the outer loop)...
for i in some_list:
if any(y['name'].lower() == findperson.lower() for y in some_list[i]):
print('Friend found')
break
else:
print('Friend not found')
... or even for the whole thing:
if any(y['name'].lower() == findperson.lower()
for i in some_list for y in some_list[i]):
print('Friend found')
else:
print('Friend not found')
If you also need the actual friend, you can use next:
for i in some_list:
friend = next((y for y in some_list[i] if y['name'].lower() == findperson.lower()), None)
if friend is not None:
print('Friend found:', friend)
break
else:
print('Friend not found')
Also works with nested generator, like with any above:
friend = next((y for i in some_list for y in some_list[i]
if y['name'].lower() == findperson.lower()),
None)
if friend is not None:
print('Friend found:', friend)
else:
print('Friend not found')
Instead of using flags and break (which only breaks the inner loop) another possible solution would be to use a function. This way you can simply use return. This also has the benefit of stopping the search once a match is found.
some_list = {'a_list': [{'name': 'Tom', 'age': 25}, {'name': 'John', 'age': 25}, {'name': 'Val', 'age': 25}],
'b_list': [{'name': 'Don', 'age': 25}, {'name': 'Tim', 'age': 25}, {'name': 'San', 'age': 25}]}
search_name = 'San'
def find_person(data, name_to_find):
for i in data:
for y in data[i]:
if y['name'].lower() == name_to_find.lower():
print('Friend found')
return
print('Friend not found')
find_person(some_list, search_name)
Try this:
some_list = {'a_list': [{'name': 'Tom', 'age': 25}, {'name': 'John', 'age': 25}, {'name': 'Val', 'age': 25}], 'b_list': [{'name': 'Don', 'age': 25}, {'name': 'Tim', 'age': 25}, {'name': 'San', 'age': 25}]}
findperson = 'San'
found = False
for i in some_list:
for y in some_list[i]:
if y['name'].lower() == findperson.lower():
print('Friend found')
found = True
if found:
break
if not found:
print('Friend not found')
for else is a good trial with break condition, but it only works when you get 1-for loop, but here you get 2-for loop, you can use a flag:
some_list = {'a_list': [{'name': 'Tom', 'age': 25}, {'name': 'John', 'age': 25}, {'name': 'Val', 'age': 25}], 'b_list': [{'name': 'Don', 'age': 25}, {'name': 'Tim', 'age': 25}, {'name': 'San', 'age': 25}]}
findperson = 'San'
found = False
for i in some_list:
for y in some_list[i]:
if y['name'].lower() == findperson.lower():
print('Friend found')
found = True
break
if found:
break
if not found:
print('Friend not found')
The best option imo is to put the nested for-loops in a function and return when you have found your friend, but if for some reason this isn't possible, you could end your nested for loops prematurely when you have found your friends without using a flag by doing something like
some_list = {'a_list': [{'name': 'Tom', 'age': 25}, {'name': 'John', 'age': 25}, {'name': 'Val', 'age': 25}],
'b_list': [{'name': 'Don', 'age': 25}, {'name': 'Tim', 'age': 25}, {'name': 'San', 'age': 25}]}
findperson = 'San'
for i in some_list:
for y in some_list[i]:
if y['name'].lower() == findperson.lower():
print('Friend found')
break
else:
continue
break
else:
print('Friend not found')

Categories