What I would like to do is loop through my_family and return the member with the highest Age.
my_family = {
"member1": {"Name":"Person1","Gender": "Male","Age": 24},
"member2": {"Name":"Person2","Gender": "Male","Age": 32},
"member3": {"Name":"Person3","Gender": "Female","Age": 62}
}
My attempt is below:
k = my_family.keys()
v = my_family.values()
def highAge():
for k,v in my_family.items():
if "Age" in my_family.items():
print("Age found")
else:
print("Failed")
highAge()
The current output is Failed.
If you don't care about keys then here is a simple solution to your problem.
my_family = {
"member1": {"Name":"Person1","Gender": "Male","Age": 24},
"member2": {"Name":"Person2","Gender": "Male","Age": 32},
"member3": {"Name":"Person3","Gender": "Female","Age": 62}
}
person_with_max_age = max(my_family.values(), key=lambda f: f["Age"])
print(person_with_max_age)
>> {'Name': 'Person3', 'Gender': 'Female', 'Age': 62}
The quick fix:
Your first 2 lines are superfluous, delete them:
k = my_family.keys()
v = my_family.values()
Then in the if statement change my_family.items() to v, and append the break command. So your full program will be
def highAge():
for k, v in my_family.items():
if "Age" in v:
print("Age found")
break
else:
print("Failed")
highAge()
You can also sort your dictionary by the age and take the last item
my_family = {
"member1": {"Name":"Person1","Gender": "Male","Age": 24},
"member3": {"Name":"Person3","Gender": "Female","Age": 62},
"member2": {"Name":"Person2","Gender": "Male","Age": 32},
}
my_family_sorted_by_age = sorted(my_family.items(), key=lambda item: item[1]["Age"])
print(my_family_sorted_by_age[-1])
Related
I have a list of Dicts as follows
[{"Sender":"bob","Receiver":"alice","Amount":50},{"Sender":"bob","Receiver":"alice","Amount":60},{"Sender":"bob","Receiver":"alice","Amount":70},{"Sender":"joe","Receiver":"bob","Amount":50},{"Sender":"joe","Receiver":"bob","Amount":150},{"Sender":"alice","Receiver":"bob","Amount":100},{"Sender":"bob","Receiver":"kyle","Amount":260}]
What i need is to sum up the totals per each unique sender/receiver pair, as well as how many total "transactions" there were per pair, as shown below in my desired output
[{"Sender":"bob","Receiver":"alice","Total":180,"Count":3},{"Sender":"joe","Receiver":"bob","Total":"200","Count":2},{"Sender":"alice","Receiver":"bob","Total":"100","Count":1}, {"Sender":"bob","Receiver":"kyle","Total":260,"Count":1}]
What i'm currently doing to get the "total" is
total = sum(a['Amount'] for a in transactions).
But this simply sums up all of the amounts across all pairs, i need the total for each unique pair of sender/receiver i would't know where to begin getting the "count" numbers, either.
Make a new dictionary where the key is the sender/receiver pair.
Iterate over the list of senders/receivers. If that sender/receiver pair does not exist in the new dict, create it. Otherwise increment the count for that pair by one.
newdict = {}
for row in transactions:
sender = row['Sender']
receiver = row['Receiver']
amount = row['Amount']
key = f'{sender},{receiver}'
if key in newdict:
newdict[key]['Total'] += amount
newdict[key]['Count'] += 1
else:
newdict[key] = {'Count': 1, 'Total': amount}
This solution produces a single dict instead of a list of dicts.
lookup for existing value and keep updating it. e.g.
transactions = [
{"Sender":"bob","Receiver":"alice","Amount":50},
{"Sender":"bob","Receiver":"alice","Amount":60},
{"Sender":"bob","Receiver":"alice","Amount":70},
{"Sender":"joe","Receiver":"bob","Amount":50},
{"Sender":"joe","Receiver":"bob","Amount":150},
{"Sender":"alice","Receiver":"bob","Amount":100},
{"Sender":"bob","Receiver":"kyle","Amount":260}
]
output = []
def find_transaction(sender: str, receiver: str):
for o in output:
if o["Sender"] == sender and o["Receiver"] == receiver:
return o
return None
for tx in transactions:
existing = find_transaction(tx["Sender"], tx["Receiver"])
if existing:
existing["Total"] += tx["Amount"]
existing["Count"] += 1
else:
output.append({
"Sender": tx["Sender"],
"Receiver": tx["Receiver"],
"Total": tx["Amount"],
"Count": 1
})
print(output)
Use a dict to group the amounts, using (sender, receiver) as key;
Rebuild your list of dicts from the dict of amounts.
ll = [{"Sender":"bob","Receiver":"alice","Amount":50},{"Sender":"bob","Receiver":"alice","Amount":60},{"Sender":"bob","Receiver":"alice","Amount":70},{"Sender":"joe","Receiver":"bob","Amount":50},{"Sender":"joe","Receiver":"bob","Amount":150},{"Sender":"alice","Receiver":"bob","Amount":100},{"Sender":"bob","Receiver":"kyle","Amount":260}]
# GROUP BY (SENDER, RECEIVER) AND REDUCE BY KEY
d = {}
for transaction in ll:
k = (transaction['Sender'], transaction['Receiver'])
d[k] = d.get(k, 0) + transaction['Amount']
# print(d)
# d = {('bob', 'alice'): 180, ('joe', 'bob'): 200, ('alice', 'bob'): 100, ('bob', 'kyle'): 260}
# REBUILD LIST OF DICT
new_ll = [{'Sender': s, 'Receiver': r, 'Amount': a} for (s,r),a in d.items()]
print(new_ll)
# [{'Sender': 'bob', 'Receiver': 'alice', 'Amount': 180}, {'Sender': 'joe', 'Receiver': 'bob', 'Amount': 200}, {'Sender': 'alice', 'Receiver': 'bob', 'Amount': 100}, {'Sender': 'bob', 'Receiver': 'kyle', 'Amount': 260}]
These kinds of group-by-key and reduce-by-key operations are extremely common. Using a dict to group by key is the best method. There is also a library function in module more_itertools:
from more_itertools import map_reduce
from operator import itemgetter
ll = ll = [{"Sender":"bob","Receiver":"alice","Amount":50},{"Sender":"bob","Receiver":"alice","Amount":60},{"Sender":"bob","Receiver":"alice","Amount":70},{"Sender":"joe","Receiver":"bob","Amount":50},{"Sender":"joe","Receiver":"bob","Amount":150},{"Sender":"alice","Receiver":"bob","Amount":100},{"Sender":"bob","Receiver":"kyle","Amount":260}]
d = map_reduce(ll, keyfunc=itemgetter('Sender', 'Receiver'), valuefunc=itemgetter('Amount'), reducefunc=sum)
print(d)
# defaultdict(None, {('bob', 'alice'): 180, ('joe', 'bob'): 200, ('alice', 'bob'): 100, ('bob', 'kyle'): 260})
new_ll = [{'Sender': s, 'Receiver': r, 'Amount': a} for (s,r),a in d.items()]
I have a dictionary with some values that are type list, i need to convert each list in another dictionary and insert this new dictionary at the place of the list.
Basically, I have this dictionary
Dic = {
'name': 'P1',
'srcintf': 'IntA',
'dstintf': 'IntB',
'srcaddr': 'IP1',
'dstaddr': ['IP2', 'IP3', 'IP4'],
'service': ['P_9100', 'SNMP'],
'schedule' : 'always',
}
I need to reemplace the values that are lists
Expected output:
Dic = {
'name': 'P1',
'srcintf': 'IntA',
'dstintf': 'IntB',
'srcaddr': 'IP1',
'dstaddr': [
{'name': 'IP2'},
{'name': 'IP3'},
{'name': 'IP4'}
],
'service': [
{'name': 'P_9100'},
{'name': 'SNMP'}
],
'schedule' : 'always',
}
So far I have come up with this code:
for k,v in Dic.items():
if not isinstance(v, list):
NewDic = [k,v]
print(NewDic)
else:
values = v
keys = ["name"]*len(values)
for item in range(len(values)):
key = keys[item]
value = values[item]
SmallDic = {key : value}
liste.append(SmallDic)
NewDic = [k,liste]
which print this
['name', 'P1']
['srcintf', 'IntA']
['dstintf', 'IntB']
['srcaddr', 'IP1']
['schedule', 'always']
['schedule', 'always']
I think is a problem with the loop for, but so far I haven't been able to figure it out.
You need to re-create the dictionary. With some modifications to your existing code so that it generates a new dictionary & fixing the else clause:
NewDic = {}
for k, v in Dic.items():
if not isinstance(v, list):
NewDic[k] = v
else:
NewDic[k] = [
{"name": e} for e in v # loop through the list values & generate a dict for each
]
print(NewDic)
Result:
{'name': 'P1', 'srcintf': 'IntA', 'dstintf': 'IntB', 'srcaddr': 'IP1', 'dstaddr': [{'name': 'IP2'}, {'name': 'IP3'}, {'name': 'IP4'}], 'service': [{'name': 'P_9100'}, {'name': 'SNMP'}], 'schedule': 'always'}
I have a dict as below:
dict1={
'item1':
{'result':
[{'val': 228, 'no': 202}]
},
'item2':
{'result':
[{'value': 148, 'year': 201}]
}
}
How can we insert a new key 'category' to each item so that the output looks like below:
output={
'item1':
{'category':
{'result':
[{'val': 228, 'no': 202}]
}
},
'item2':
{'category':
{'result':
[{'value': 148, 'year': 201}]
}
}
}
Currently, i have key:value and im looking to insert newkey which takes same value, key:newkey:value
I tried to do dict1['item1']['category1'] but this is adding a new key value pair.
Use to modify in-place the existing dictionary dict1:
for key, value in dict1.items():
dict1[key] = { "category" : value }
print(dict1)
Output
{'item1': {'category': {'result': [{'val': 228, 'no': 202}]}}, 'item2': {'category': {'result': [{'value': 148, 'year': 201}]}}}
As an alternative use update:
dict1.update((k, {"category": v}) for k, v in dict1.items())
Note that update receives both a dictionary or an iterable of key/value pairs, from the documentation:
update() accepts either another dictionary object or an iterable of
key/value pairs (as tuples or other iterables of length two).
Finally in Python 3.9+, you can use the merge operator (|=), as below:
dict1 |= ((k, {"category": v}) for k, v in dict1.items())
Try:
out = {k: {"category": v} for k, v in dict1.items()}
print(out)
Prints:
{
"item1": {"category": {"result": [{"val": 228, "no": 202}]}},
"item2": {"category": {"result": [{"value": 148, "year": 201}]}},
}
data = [{"id": "78ab45",
"name": "Jonh"},
{"id": "69cd234457",
"name": "Joe"}]
I want my function to return the largest value lengths for each key from all dictionaries:
expected_output = [
{ "size": 10, "name": "id" }, #because the length of the largest "id" value is 10
{ "size": 4, "name": "name" }, #because the length of the largest "name" value is 4
]
My code so far:
def my_func(data):
headers_and_sizes = []
for item in data:
for key, value in item.items():
headers_and_sizes.append({"size": f'{len(value)}', "name": key})
if int(headers_and_sizes[0]["size"]) < len(value):
headers_and_sizes[0]["size"] = len(value)
return headers_and_sizes
Gives me this:
[{'size': '6', 'name': 'id'}, {'size': '4', 'name': 'name'}, {'size': '10', 'name': 'id'}, {'size': '3', 'name': 'name'}]
How can I fix that so that it will return the values as in expected_output?
You'll want to be updating a dictionary that stores each key mapped to the maximum length seen for that key thus far.
data = [
{
"id": "78ab45",
"name": "Jonh",
},
{
"id": "69cd234457",
"name": "Joe",
},
]
key_to_max_len = {}
for datum in data:
for key, val in datum.items():
if key not in key_to_max_len or len(val) > key_to_max_len[key]:
key_to_max_len[key] = len(val)
key_size_arr = [{"size": val, "name": key} for key, val in key_to_max_len.items()]
you can get the max value for id and name like below code, and structure the output accordingly
>>> data
[{'id': '78ab45', 'name': 'Jonh'}, {'id': '69cd234457', 'name': 'Joe'}]
id = max(map(lambda x:len(x['id']), data))
name = max(map(lambda x:len(x['name']), data))
>>> id
10
>>> name
4
You can use list comprehension to form a tuple with ids and names:
names_ids = [(eachdict['id'],eachdict['name']) for eachdict in data]
Format the output to have the desired shape (dictionaries), find the max length (using the max() function, passing it the lengths of names and ids, using another list comprehension, inside max()):
expected_output = \
[{"size":max([len(each[0]) for each in names_ids]),"name":"id"},
{"size":max([len(each[1]) for each in names_ids]),"name":"name"}]
Output will be:
[{'name': 'id', 'size': 10}, {'name': 'name', 'size': 4}]
Using the following:
keys = list(data[0].keys())
output = {key:-1 for key in keys}
for d in data:
for k in d.keys():
if len(d[k]) > output[k]:
output[k] = len(d[k])
Will output:
{'id': 10, 'name': 4}
I think the easiest method here is pandas...
import pandas as pd
df = pd.DataFrame(data)
out = [{'size': df['id'].str.len().max(), 'name':'id'},
{'size': df['name'].str.len().max(), 'name':'name'}]
output:
[{'size': 10, 'name': 'id'}, {'size': 4, 'name': 'name'}]
or for addt'l names..
[{'size':df[col].str.len().max(), 'name':col} for col in df.columns]
Here is how you can use a nested dictionary comprehension:
data = [{"id": "78ab45",
"name": "Jonh"},
{"id": "69cd234457",
"name": "Joe"}]
expected_output = [{'size': len(max([i[k] for i in data], key=len)),
'name': k} for k in data[0]]
print(expected_output)
Output:
[{'size': 10, 'name': 'id'},
{'size': 4, 'name': 'name'}]
Considering I have
users = \
{
'Sam': {
'age': 19,
'location': 'Flodira',
'country': 'United States'
},
'Max': {
'age': 16,
'location': 'Sydney',
'country': 'Australia'
}
}
def getUserValue(query):
return users[query]
getUserValue(['Sam', 'location'])
How could I do this? I know I could straightly do users['Sam']['location'], what I would like to do is get Sam's location via a list object.
Here's a generic solution that handles different levels of nesting:
def getUserValue(users, query):
v = users
for i in query:
v = v[i]
return v
print(getUserValue(users, ['Sam', 'location']))
# Flodira
def getUserValue(query):
assert(len(query) == 2)
return users[query[0]][query[1]]
Is that what you're looking for?
You could solve this problem with recursion:
def getByList(d, l):
if len(l) == 0:
return d
else:
return getByList(d[l[0]], l[1:])
def getUserValue(query):
return getByList(users, query)
For a more general solution than Jared's, you could use list unpacking with a recursive function..
def getUserValue(dic, lis):
if len(lis) > 1:
return getUserValue(dic[lis[0]], lis[1:])
else:
return dic[lis[0]]
How about the following?
users = \
{
'Sam': {
'age': 19,
'location': 'Flodira',
'country': 'United States'
},
'Max': {
'age': 16,
'location': 'Sydney',
'country': 'Australia'
}
}
def getUserValue(my_args):
item = users[my_args.pop(0)]
while my_args:
item = item[my_args.pop(0)]
return item
print(getUserValue(['Sam', 'location'])) # prints -> Flodira
keeps treating item as a dictionary until the passed list is depleted.
You could use plain old reduce and operator.getitem
import operator
def getUserValue(dic, lis):
return reduce(operator.getitem, lis, dic)