Filter list of dictionaries - python

This is my example:
dictlist = [{'first': 'James', 'last': 'Joule'},
{'first': 'James','last': 'Watt'},
{'first': 'Christian','last': 'Doppler'}]
I am trying to get the last name. If this was in a model, the code would be:
getdata = Name.objects.filter(name="Christian")
getLastName = getdata.last
and I would get "Doppler".

This is very simple solution with list comprehension:
>>> dictlist = [{'first': 'James', 'last': 'Joule'}, {'first': 'James','last': 'Watt'},{'first': 'Christian','last': 'Doppler'}]
>>> [x['last'] for x in dictlist if x['first'] == 'Christian']
['Doppler']

dictlist = [{'first': 'James', 'last': 'Joule'}, {'first': 'James','last': 'Watt'},{'first': 'Christian','last': 'Doppler'}]
the_jameses = [d for d in dictlist if d['first'] == 'James']
Where the resulting list contains only:
[{'first': 'James', 'last': 'Joule'}, {'first': 'James', 'last': 'Watt'}]

To start with, we can have a simple script that just uses the built-in python filter method, and this might already be sufficient:
fl = list(filter(lambda x: x['first'] == 'Christian', dictlist))
# you can't use `.property` because this is a dictionary, not a object
fl[0]['last']
# returns Doppler
I realize your example is a Django code, so if you want to make this more dynamic so that you are able to filter by any key in the dictionary:
def dict_filter(dictlist: list, key: str, value: str) -> list:
return list(filter(lambda x: x.get(key) == value, dictlist))
dict_filter(dictlist, 'first', 'Christian')
# similar to django's filter method returns a queryset, this returns a list:
# [{'first': 'Christian', 'last': 'Doppler'}]
dict_filter(dictlist, 'last', 'Doppler')
# returns [{'first': 'Christian', 'last': 'Doppler'}]
dict_filter(dictlist, 'last', 'notfound')
# returns []
And an example to use python filter method to create a similar function to Django's QuerySet.get method:
def dict_get(dictlist: list, key: str, value: str) -> list:
ret = list(filter(lambda x: x.get(key) == value, dictlist))
if len(ret) == 0:
raise Exception('Not Found')
if len(ret) > 1:
raise Exception(f'Found more than 1 object with {key}={value}')
return ret[0]
dict_get(dictlist, 'first', 'Christian')
# returns {'first': 'Christian', 'last': 'Doppler'}
dict_get(dictlist, 'first', 'Christians')
# raises Exception: Not Found
dict_get(dictlist, 'first', 'James')
# raises Exception: Found more than 1 object with first=James
Hope this is helpful to you!

Something like this should work
last_name = ''
for d in dictList:
if d['first'] == 'Christian':
last_name = d['last']
break

I sometimes like to use next:
next((d['last'] for d in dictlist if d['first'] == 'Christian'), None)
# 'Doppler'
The first argument is an iterator and the second (optional) argument is the default value returned if no matching entry is found.
Note: this will only return the first matching result. So it wouldn't be good if you expect to have multiple records matching your "query".

Hope this is helpful to you!!
"; my_dict=[
{
'username':"Siva",
'phoneno':"12345678915",
'city':"Chennai"
},
{
'username':"Sundhar",
'phoneno':"12345678917",
'city':"Vellore"
},
{
'username':"cockroach",
'phoneno':"12345668919",
'city':"Chennai"
},
{
'username':"oggy",
'phoneno':"12345678917",
'city':"Chennai"
}
]
";phoneno="12345678917"
result = [user['username'] for user in my_dict if user['phoneno']== phoneno]

for comp in dictlist:
if comp["first"] == 'Christian':
return comp["last"]

Related

How to convert list of elements into dictionary of dictionaries

How to turn this list -
list = ['your name', 'mother', 'age', '43']
into this dictionary of dictionaries -
dict = {'your name':
{'mother':
{'age': '43'}
}
}
One option is to iterate backwards over the list, and continuously update the result dict D:
L = ['your name', 'mother', 'age', '43']
D = L[-1] # '43'
for k in L[-2::-1]:
D = {k: D} # {'age': D}... {'mother': D}...
print(D)
Out:
{'your name': {'mother': {'age': '43'}}}
You can just hardcode the logic and then run this in a loop.
l = ['your name', 'mother', 'age', '43']
d = {}
d[l[0]] = {
l[1]: {
l[2]: l[3]
}
}

Update a list of Dict based on another Dict

I have a dict as follows.
dict = {'P': ['Demo'], 'Q': ['PMS']}
And I have a list of Dict as follows.
all = [{'Name': 'PMS'}, {'Name': 'Demo'}]
I need to have the dict's respective value in all as bellow.
new_list = [{'Name': 'PMS','Code': 'Q'}, {'Name': 'Demo','Code': 'P'}]
In this specific case, given that the values are just strings and therefore hashable objects, you can use a dictionary of reverse mappings. Be aware that it could not be used if the values were not hashable.
dct = {'P': ['Demo'], 'Q': ['PMS']}
all = [{'Name': 'PMS'}, {'Name': 'Demo'}]
reverse_mapping = {v[0]:k for k, v in dct.items()}
new_list = [d.copy() for d in all]
for d in new_list:
d['Code'] = reverse_mapping[d['Name']]
print(new_list)
This gives:
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]
dct = {'P': ['Demo'], 'Q': ['PMS']}
all_ = [{'Name': 'PMS'}, {'Name': 'Demo'}]
out = [dict(**l, Code=next(k for k, v in dct.items() if l['Name'] in v)) for l in all_]
print(out)
Prints:
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]
Or: you can make temporary dictionary:
tmp = {v[0]:k for k, v in dct.items()}
out = [dict(**l, Code=tmp[l['Name']]) for l in all_]
print(out)
You could make an inverted dictionary of codes, then go through the list of dictionaries and add the codes in:
codes = {"P": ["Demo"], "Q": ["PMS"]}
lst = [{"Name": "PMS"}, {"Name": "Demo"}]
inverted_codes = {value: key for key, values in codes.items() for value in values}
# {'Demo': 'P', 'PMS': 'Q'}
for dic in lst:
code = dic["Name"]
dic["Code"] = inverted_codes[code]
print(lst)
Output
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]

Change value in dictionary

I would like to know how I can change a value in a dictionary using list of keys and 1 value
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
string1 = 'bob.name.first=Bob'
string1 = string.split('=')
string2 = string1[0].split('.')
string2.append(string[1])
Here I end up with a list of 4 items, the first 3 are keys and the last is the value.
How can I use this given list to change the value in my_dict considering that the given list keys number can be changed for example if I want to change bob.job=QA
You can write:
string1 = 'bob.name.first=Bob'
string1,string2 = string1.split('=')
string1 = string1.split('.')
my_dict[string1[0]][string1[1]][string1[2]] = string2
I suppose the following function is what you are looking for, it works with any number of keys and creates intermediates dictionaries if not exist yet.
d = {
'bob': {
'name': {
'first': 'FirstName',
'last': 'LastName'
},
'job': 'Developer'
}
}
def update_dict_by_expr(d, expr):
keys_value = expr.split('=')
keys = keys_value[0].split('.')
value = keys_value[1]
item = d
while len(keys) > 1:
key = keys.pop(0)
if key not in item:
item[key] = {}
item = item[key]
key = keys[0]
item[key] = value
print(d)
update_dict_by_expr(d, 'bob.name.first=Bob Junior')
update_dict_by_expr(d, 'bob.name.birth.date=01/01/2017')
update_dict_by_expr(d, 'bob.name.birth.place=NYC')
print(d)
You want a dict with keys that can be accessed as attributes. You can achieve that by subclassing dict class, and add support for your need. I think this is more pythonic solution as it is much more intuative:
class MyDict(dict):
def __getattr__(self, attr):
return self[attr] if attr in self.keys() else None
def __setattr__(self, attr, value):
self[attr] = value
my_dict = MyDict({
'bob': MyDict(
{'name':
MyDict({'first': 'FirstName', 'last': 'LastName'}),
'job':'Developer'})})
>>> my_dict.bob
{'job': 'Developer', 'name': {'last': 'LastName', 'first': 'FirstName'}}
>>> my_dict.bob.job
'Developer'
>>> my_dict.bob.name
{'last': 'LastName', 'first': 'FirstName'}
It does require some overhead, as you will need to build your dicts based on MyDict. Regular dicts won't work if added to this dict.
This supports setting a new value as well:
>>> my_dict.bob.job = 'QA'
>>> my_dict.bob.job
'QA'
If you want to update Bob's job you can access it using my_dict['bob']['job']
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
my_dict['bob']['job'] = 'QA'
print(my_dict)
>> {'bob': {'name': {'last': 'LastName', 'first': 'FirstName'}, 'job': 'QA'}}
or by splitting your string:
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
bobjob_key_value = 'bob.job=QA'
key, value = bobjob_key_value.split('=')
key = key.split('.')
my_dict[key[0]][key[1]] = value
print(my_dict)
>> {'bob': {'job': 'QA', 'name': {'last': 'LastName', 'first': 'FirstName'}}}
import yaml
def get_dictionary_replace_value(file, new_value, strip_qoutes=True):
with open(file, 'r') as rf:
yaml_doc = yaml.load(rf)
rf.close()
key, value = new_value.split('=')
keys = key.split('.')
inner_dict = yaml_doc
for i in keys[:-1]:
inner_dict = inner_dict[i]
inner_dict[keys[-1]] = value
with open(file, 'w') as wf:
if strip_qoutes:
wf.write(yaml.dump(yaml_doc,
default_flow_style=False).replace("'", "").replace('"', ""))
else:
wf.write(yaml.dump(yaml_doc, default_flow_style=False))
wf.close()

KeyError: 'name' Why can't I use 'name'?

I wanna make a dictionary has name's key & data.In views.py I wrote
data_dict ={}
def try_to_int(arg):
try:
return int(arg)
except:
return arg
def main():
book4 = xlrd.open_workbook('./data/excel1.xlsx')
sheet4 = book4.sheet_by_index(0)
data_dict_origin = OrderedDict()
tag_list = sheet4.row_values(0)[1:]
for row_index in range(1, sheet4.nrows):
row = sheet4.row_values(row_index)[1:]
row = list(map(try_to_int, row))
data_dict_origin[row_index] = dict(zip(tag_list, row))
if data_dict_origin['name'] in data_dict:
data_dict[data_dict_origin['name']].update(data_dict_origin)
else:
data_dict[data_dict_origin['name']] = data_dict_origin
main()
When I printed out data_dict,it is
OrderedDict([(1, {'user_id': '100', 'group': 'A', 'name': 'Tom', 'dormitory': 'C'}), (2, {'user_id': '50', 'group': 'B', 'name': 'Blear', 'dormitory': 'E'})])
My ideal dictionary is
dicts = {
Tom: {
'user_id': '100',
'group': 'A',
'name': 'Tom',
'dormitory': 'C'
},
Blear: {
},
}
How should I fix this?What should I write it?
The code is using the wrong key in the dictionary. The keys are 1, 2, and do not have the name key. You can use this code instead:
for value in data_dict.values():
if value['name'] in data_dict:
data_dict[value['name']].update(value)
else:
data_dict[value['name']] = value
Your data_dict_origin has numbers as keys and dicts as values (which technically makes it a sparse array of dicts). The "name" key exists in those dicts, not in your data_dict.

Python dictionary isn't updating

def mergeDict(object):
dict1 = {}
for i in range(len(object)):
dict1.update({'id': object[i].id, 'name': object[i].name, 'age': object[i].age, 'location': object[i].location})
return dict1
merged_dict = mergeDict(details_sorted)
But this doesn't work.
I want to get something like this:
{1: {'id': 1, 'name': 'John', 'age': '25'; 'location': 'somewhere'},
2: {'id': 2, 'name': ......}}
It looks like the return statement is in the for loop, which means it will only ever return the update of the first dict.
You don't want to update the dict; you just want to insert a value on key i. Also, the return goes after the for, not in it. Here is a modified version:
def mergeDict(object):
dict1 = {}
for i in range(len(object)):
dict1[i] = {'id': object[i].id, 'name': object[i].name, 'age': object[i].age, 'location': object[i].location}
return dict1
merged_dict = mergeDict(details_sorted)
Your update version would have updated the id, name, age and location keys of dict1 -- and you don't want that. You want to update the id key of dict1 with another dictionary containing the keys id, name, age and location.
Do a bit of experiment.
def mergeDict(object):
dict1 = {}
dict1.update({'id': 'object[i].id', 'name': 'object[i].name', 'age': 'object[i].age', 'location': 'object[i].location'})
dict1.update({'id': 'object[j].id', 'name': 'object[j].name', 'age': 'object[j].age', 'location': 'object[j].location'})
return dict1
merged_dict = mergeDict(None)
print merged_dict
Output:
{'name': 'object[j].name', 'age': 'object[j].age', 'location': 'object[j].location', 'id': 'object[j].id'}
Errors:
Only last object values are retained as the keys are same for all objects. So the for loop has no effect.
It's like saying
x = {}
x['k'] = y
x['k'] = z
There is only one key - k and it's latest value is z
One-liner in Python 3.0:
merged_dict = {i: dict(id=o.id, name=o.name, age=o.age, location=o.location)
for i, o in enumerate(details_sorted)}
If the result keys are consecutive integers, why not a list instead of dict?
merged = [ dict(id=o.id, name=o.name, age=o.age, location=o.location)
for i, o in enumerate(details_sorted) ]
A list has the added benefit of preserving sort order.

Categories

Resources