I have a dictionary of dictionaries.
Sample:
keyList = ['0','1','2']
valueList = [{'Name': 'Nick', 'Age': 39, 'Country': 'UK'}, {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}, {'Name': 'Dave', 'Age': 23, 'Country': 'UK'}]
d = {}
for i in range(len(keyList)):
d[keyList[i]] = valueList[i]
Output:
{'0': {'Name': 'Nick', 'Age': 39, 'Country': 'UK'}, '1': {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}, '2': {'Name': 'Dave', 'Age': 23, 'Country': 'UK'}}
I want to do two things:
filter by one string or int value in a value e.g. Name, ignoring case. I.e. remove any key/value where a string/int is found. So if 'Nick' is found in Name, remove the key '0' and its value completely:
{'1': {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}, '2': {'Name': 'Dave', 'Age': 23, 'Country': 'UK'}}
The same as above, but with a list of strings instead. I.e. filter and remove any keys where any of the following strings ["uK", "Italy", "New Zealand"] appear in Country, ignoring case.
{'1': {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}}
I was hoping the below would work for one string, but I think it only works if it is just one dictionary rather than a dictionary of dictionaries, so its not working for me:
filtered_d = {k: v for k, v in d.items() if "nick".casefold() not in v["Name"]}
Any suggestions? Many thanks
Assuming there is one level of nesting in the dictionary (not a dictionary of dictionaries of dictionaries), you could use the following function which iterates over the keys and filters as per the supplied values:
from typing import List
def remove_from_dict(key_name: str, values: List[str], dictionary: dict):
values = [value.casefold() for value in values]
filtered_dict = {
key: inner_dict
for key, inner_dict in dictionary.items()
if inner_dict[key_name].casefold() not in values
}
return filtered_dict
dictionary = {
"0": {"Name": "Nick", "Age": 39, "Country": "UK"},
"1": {"Name": "Steve", "Age": 19, "Country": "Spain"},
"2": {"Name": "Dave", "Age": 23, "Country": "UK"},
}
# Output: {'1': {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}, '2': {'Name': 'Dave', 'Age': 23, 'Country': 'UK'}}
print(remove_from_dict("Name", ["Nick"], dictionary))
# Output: {'1': {'Name': 'Steve', 'Age': 19, 'Country': 'Spain'}}
print(remove_from_dict("Country", ["uK", "Italy", "New Zealand"], dictionary))
Update:
If we want to account for partial matches, we have to use re module.
import re
from typing import List, Optional
dictionary = {
"0": {"Name": "Nick", "Age": 39, "Country": "UK"},
"1": {"Name": "Steve", "Age": 19, "Country": "Spain"},
"2": {"Name": "Dave", "Age": 23, "Country": "UK"},
}
def remove_from_dict(
key_name: str,
values: List[str],
dictionary: dict,
use_regex: Optional[bool] = False,
):
values = [value.casefold() for value in values]
regular_comparator = lambda string: string.casefold() not in values
# if the string matches partially with anything in the list,
# we need to discard that dictionary.
regex_comparator = lambda string: not any(
re.match(value, string.casefold()) for value in values
)
comparator = regex_comparator if use_regex else regular_comparator
filtered_dict = {
key: inner_dict
for key, inner_dict in dictionary.items()
if comparator(inner_dict[key_name])
}
return filtered_dict
# Output: {}, all dictionaries removed
print(remove_from_dict("Country", ["uK", "Spa"], dictionary, use_regex=True))
Related
I have this list of dictionary and I would like to get those with the same exact value of 'name' and 'school' into a new list and also getting their 'age' merged into a list as well and the rest of the dictionary that is not identical to just add into the list as per usual..
Here is an example of the list of dictionary
[{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
and I would like it to make it into something like this..
[{'name': 'Jane', 'age': [12,14,16], 'school': 'SIT'}, {'name': 'John', 'age': 13, 'school': 'SMU'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
using Python.. please help!
tried using counter, loops but still can't get it to work..
You could use itertools.groupby().
Example:
import itertools
from pprint import pprint
data = [{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
keyfunc = lambda x: (x["name"], x["school"])
# needs to be sorted to use groupby
data.sort(key=keyfunc)
output = []
for k,v in itertools.groupby(data, key=keyfunc):
this_group = {
"name": k[0],
"school": k[1],
"age": [i["age"] for i in v],
}
output.append(this_group)
pprint(output)
The output is:
[{'age': [12, 14, 16], 'name': 'Jane', 'school': 'SIT'},
{'age': [13], 'name': 'John', 'school': 'NUS'},
{'age': [13], 'name': 'John', 'school': 'SMU'}]
If you wish to go with the solution based on a buffer dictionary, please check out the dict.setdefault() method.
Example:
buffer = {}
for i in data:
buffer.setdefault((i["name"], i["school"]), []).append(i["age"])
For reference:
https://docs.python.org/3/library/itertools.html#itertools.groupby
https://docs.python.org/3/library/stdtypes.html#dict.setdefault
x = [{'name': 'Jane', 'age':12, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'SMU'},{'name': 'Jane', 'age':14, 'school': 'SIT'}, {'name': 'Jane', 'age':16, 'school': 'SIT'}, {'name': 'John', 'age':13, 'school': 'NUS'}]
new_x = {}
for r in x:
if r['name'] in new_x.keys():
if not isinstance(new_x[r['name']]['age'], list):
new_x[r['name']]['age'] = [new_x[r['name']]['age']]
if r['age'] not in new_x[r['name']]['age']:
new_x[r['name']]['age'].append(r['age'])
else:
new_x[r['name']] = {'age': r['age'], 'school': r['school']}
z = [v.update(name=k) for k, v in new_x.items()]
z = [v for k, v in new_x.items()]
Here is a universal solution to your problem. Only name and school are considered "special". All other keys, like age are converted to list when a new value has to be added.
l = [
{"name": "Jane", "age": 12, "school": "SIT"},
{"name": "John", "age": 13, "school": "SMU"},
{"name": "Jane", "age": 14, "school": "SIT"},
{"name": "Jane", "age": 16, "school": "SIT"},
{"name": "John", "age": 13, "school": "NUS"},
]
r = {}
for x in l:
id = f"{x['name']}-{x['school']}"
if id in r:
for k,v in x.items():
if k not in ["name", "school"]:
if k in r[id]:
if isinstance(r[id][k], list):
r[id][k].append(v)
else:
r[id][k] = [r[id][k], v]
else:
r[id][k] = v
else:
r[id] = x
result = [x for x in r.values()]
Hi I am looking to extract list of all keys from a List of dictionaries and their corresponding counts using Python. Used below code but counden't do it can some one help me in this regard
The Data looks like this,
people = [{'name': "Tom", 'age': 10, "city" : "NewYork"},
{'name': "Mark", 'age': 5, "country" : "Japan"},
{'name': "Pam", 'age': 7, "city" : "London"},
{'name': "Tom", 'hight': 163, "city" : "California"},
{'name': "Lena", 'weight': 45, "country" : "Italy"},
{'name': "Ben", 'age': 17, "city" : "Colombo"},
{'name': "Lena", 'gender': "Female", "country" : "Italy"},
{'name': "Ben", 'gender': "Male", "city" : "Colombo"}]
def search(name):
p_count = 0
for p in people:
if p['name'] == name:
p_count = p_count+1
return p, p_count
search("Pam")
def search1(list_dict):
for i in list_dict:
def getList(i):
return i.keys()
search1(people)
I want out put like the following,
name: 8, age: 4, City:3, Country: 2 etc..
I am new to this can some one help me in this
Just create a temporary dictionary to hold the count result, and for each key in each dictionary of the list, increase the the count by 1 using dict.get with default value as 0, finally return this dictionary.
def getKeyCount(lst):
out = {}
for d in lst:
for k in d.keys():
out[k] = out.get(k, 0) + 1
return out
getKeyCount(people)
#output
{'name': 8, 'age': 4, 'city': 5, 'country': 3, 'hight': 1, 'weight': 1, 'gender': 2}
You can make a hash table, and iterate over the keys of each
hash = {}
for d in list_dict:
for k in d.keys():
if k not in hash:
hash[k] = 0
hash[k] += 1
print(hash)
I have a JSON:
[{'job': 'fireman', 'salary': 30000', 'country':'USA'}, {'job': 'doctor', 'salary': '50000': 'country': 'Canada'},{'job': 'fireman', 'salary': 60000', 'country':'France'}, {'job': 'Engineer', 'salary': 45000', 'country':'Mexico'} ]
I want to combine the duplicate values and create a JSON like:
[
{"job": "fireman",
"sumamry": [{"country": "USA", "Salary": 40000}, {"Country": "France", "Salary": 60000}]
"total" : 100000},
{"job": "doctor",
"summary": [{"country": "Canada", "Salary": 50000}]
"total" : 50000},
....
]
Try this:
non_summarized = [{'job': 'fireman', 'salary': 30000, 'country':'USA'}, {'job': 'doctor', 'salary': 50000, 'country': 'Canada'},{'job': 'fireman', 'salary': 60000, 'country':'France'}, {'job': 'Engineer', 'salary': 45000, 'country':'Mexico'}]
# sort the list of dictionary base on job keys, so we can loop in the order
non_summarized = sorted(non_summarized, key = lambda i: i['job'])
summarized = list()
last_value = dict()
for d in non_summarized:
# check if the last value has the same job or not
# if not then create a new dict value and update with new information
if last_value.get('job') != d.get('job'):
last_value = {
'job': d.get('job'),
'total': 0,
'summary': list()
}
summarized.append(last_value)
last_value['total'] += d.get('salary', 0)
last_value['summary'].append({
'country': d.get('country'),
'salary': d.get('salary')
})
print(summarized)
Please let me know if you need any clarification.
I need to change values in a nested dictionary. Consider this dictionary:
stocks = {
'name': 'stocks',
'IBM': 146.48,
'MSFT': 44.11,
'CSCO': 25.54,
'micro': {'name': 'micro', 'age': 1}
}
I need to loop through all the keys and change the values of all the name keys.
stocks.name
stocks.micro.name
These keys need to be changed. But, I will not know which keys to change before hand. So, I'll need to loop through keys and change the values.
Example
change_keys("name", "test")
Output
{
'name': 'test',
'IBM': 146.48,
'MSFT': 44.11,
'CSCO': 25.54,
'micro': {'name': 'test', 'age': 1}
}
A recursive solution that supports unknown number of nesting levels:
def change_key(d, required_key, new_value):
for k, v in d.items():
if isinstance(v, dict):
change_key(v, required_key, new_value)
if k == required_key:
d[k] = new_value
stocks = {
'name': 'stocks',
'IBM': 146.48,
'MSFT': 44.11,
'CSCO': 25.54,
'micro': {'name': 'micro', 'age': 1}
}
change_key(stocks, 'name', 'new_value')
print(stocks)
# {'name': 'new_value',
# 'MSFT': 44.11,
# 'CSCO': 25.54,
# 'IBM': 146.48,
# 'micro': {'name': 'new_value',
# 'age': 1}
# }
def changeKeys(d, repl):
for k,v in zip(d.keys(),d.values()):
if isinstance(v, dict):
changeKeys(v,repl)
elif k == "name":
d[k]= repl
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()