iterate through a dictionary inside a dictionary in python - python

So let's say i have
dictionary = {
'Moe': {
'name':'moe',
'age':24,
'married':False
},
'Jon': {
'name':'jon',
'age':22,
'married':False
},
'andrew':
{'name':'andrew',
'age':27,
'married':True
}
}
Suppose that i want to iterate through the dictionary to find out how many person is married in this dictionary, how can i do it?

You could use the following generator comprehension to lookup married in the inner dictionaries setting the default value to 0, and take the sum:
sum(i.get('married', 0) for i in dictionary.values())
#1

result = 0
for x in dictionary:
if dictionary[x]['married'] == True:
result += 1
print(result)

One way of doing it is like this:
n_married = 0
for key, item in d.items():
name, age, married = item
n_married += 1 if married else 0
print(n_married)

You need:
count = 0
for v in dictionary.values():
if v['married']:
count += 1
print(count)

Related

Most efficient method to find values in nested dict

Let's say I have the dict below
{
"1": {
"rarity": 1
},
"2": {
"rarity": 2
}
}
and I want to find the amount of times rarity is 1. Instead of doing
count = 0
for x in dict.values():
if x['rarity'] == 1:
count += 1
return count
Is there a better way to do this? I found this post about using map, but I'm not sure how to get it to work with a nested dictionary.
You can write it much shorter:
count = sum(v["rarity"] == 1 for v in d.values())
from rioV8's comment, with inspiration from Mateen Ulhaq's comment
You can use the following helper function with the map.
def functionHelper(value):
if value["rarity"] == 1:
return 1
return 0
sum(map(functionHelper, d.values()))
or you can use one of these:
sum(map((1).__eq__, [v["rarity"] for v in d.values()]))
sum(v["rarity"] == 1 for v in d.values())

How to find the highest value element in a list with reference to a dictionary on python

How do I code a function in python which can:
iterate through a list of word strings which may contain duplicate words and referencing to a dictionary,
find the word with the highest absolute sum, and
output it along with the corresponding absolute value.
The function also has to ignore words which are not in the dictionary.
For example,
Assume the function is called H_abs_W().
Given the following list and dict:
list_1 = ['apples','oranges','pears','apples']
Dict_1 = {'apples':5.23,'pears':-7.62}
Then calling the function as:
H_abs_W(list_1,Dict_1)
Should give the output:
'apples',10.46
EDIT:
I managed to do it in the end with the code below. Looking over the answers, turns out I could have done it in a shorter fashion, lol.
def H_abs_W(list_1,Dict_1):
freqW = {}
for char in list_1:
if char in freqW:
freqW[char] += 1
else:
freqW[char] = 1
ASum_W = 0
i_word = ''
for a,b in freqW.items():
x = 0
d = Dict_1.get(a,0)
x = abs(float(b)*float(d))
if x > ASum_W:
ASum_W = x
i_word = a
return(i_word,ASum_W)
list_1 = ['apples','oranges','pears','apples']
Dict_1 = {'apples':5.23,'pears':-7.62}
d = {k:0 for k in list_1}
for x in list_1:
if x in Dict_1.keys():
d[x]+=Dict_1[x]
m = max(Dict_1, key=Dict_1.get)
print(m,Dict_1[m])
try this,
key, value = sorted(Dict_1.items(), key = lambda x : x[1], reverse=True)[0]
print(f"{key}, {list_1.count(key) * value}")
# apples, 10.46
you can use Counter to calculate the frequency(number of occurrences) of each item in the list.
max(counter.values()) will give us the count of maximum occurring element
max(counter, key=counter.get) will give the which item in the list is
associated with that highest count.
========================================================================
from collections import Counter
def H_abs_W(list_1, Dict_1):
counter = Counter(list_1)
count = max(counter.values())
item = max(counter, key=counter.get)
return item, abs(count * Dict_1.get(item))

Nested Dictionary for loop

I'm new to programming. I'm trying to figure out how to subtract 'budgeted' from 'actual' and then update the value to 'variance' using a nested for loop. However, I've read that it isn't the best practice to change a dictionary while iterating. So far, I've been stumped on how to proceed.
for i in properties:
for j in properties[i]:
if j == "actual":
sum = properties[i][j]
print('\nActual:' , sum)
if j == "budgeted":
sum_two = properties[i][j]
print('Budgeted:' , sum_two)
diff = sum_two - sum
print('Variance:', diff)
default_value = 0
properties = {587: {'prop_name': 'Collington'}, 'rental_income': {'apartment_rent': '5120-0000', 'resident_assistance': '5121-0000', 'gain_loss': '5120-0000'}, 51200000: {'actual': 29620, 'budgeted': 30509, 'variance': default_value}, 51210000: {'actual': 25620, 'budgeted': 40509, 'variance': default_value}, ............
just iterate through the dictionary and check if in the inner dictionary, if actual, variance and budgeted exists or not, if yes then modify the variance value
for k, v in properties.items():
if (('actual' in v.keys()) and ('variance' in v.keys()) and ('budgeted' in v.keys())):
properties[k]['variance'] = properties[k]['actual']-properties[k]['budgeted']
There is nothing wrong with modifying the values inside a dictionary while iterating. The only thing that is not recommend is modifying the dictionary itself, that is adding/removing elements.
Try something like:
for i in properties:
properties[i]['variance'] = properties[i]['budgeted'] - properties[i]['actual']
If you aren't sure that bugeted and actual exist in the dictionaries, you should catch the KeyError and handle approprately:
for i in properties:
try:
properties[i]['variance'] = properties[i]['budgeted'] - properties[i]['actual']
except KeyError:
properties[i]['variance'] = -1 # Set to some special value or just pass
Your data is in a strange format, I always try to group like objects together in dictionaries rather than have metadata and "lists" of items in the same level of a dictionary. This will work for you though:
for prop in properties:
p = properties[prop]
if 'actual' or 'budgeted' in p.keys():
# get() wont error if not found, also default to 0 if not found
p['variance'] = p.get('budgeted', 0) - p.get('actual', 0)
import json
print(json.dumps(properties, indent=4))
Output:
{
"587": {
"prop_name": "Collington"
},
"rental_income": {
"apartment_rent": "5120-0000",
"resident_assistance": "5121-0000",
"gain_loss": "5120-0000"
},
"51200000": {
"actual": 29620,
"budgeted": 30509,
"variance": 889
},
"51210000": {
"actual": 25620,
"budgeted": 40509,
"variance": 14889
}
}
sum = None
sum_two = None
for i in properties:
for j in i:
if j=="actual":
sum = properties [i]["actual"]
print('\nActual:' , sum)
if j == "budgeted":
sum_two = properties[i]["budgeted"]
print('Budgeted:' , sum_two)
diff = sum_two - sum
print('Variance:', diff)
I didn't get what mean exactly, but this should work.

Count occurance of an item in a list and store it in another list if it is exists more than once

Let's say I have the following list.
my_list = ['4/10', '8/-', '9/2', '4/11', '-/13', '19/10', '25/-', '26/-', '4/12', '10/16']
I would like to check the occurrence of each item and if it exists more than once I would like to store it in a new list.
For example from the above list, 4 is existed 3 times before / as 4/10, 4/11, 4/12. So I would like to create a new list called new list and store them as new_list = '4/10', '4/11', '4/12, 19/10'.
An additional example I want to consider also /. if 10 exist twice as 4/10 and 10/16 I don want to consider it as a duplicate since the position after and before / is different.
If there any way to count the existence of an item in a list and store them in a new list?
I tried the following but got an error.
new_list = []
d = Counter(my_list)
for v in d.items():
if v > 1:
new_list.append(v)
The error TypeError: '>' not supported between instances of 'tuple' and 'int'
Can anyone help with this?
I think below code is quite self-explanatory. It will work alright. If you have any issues or need clarification, feel free to ask.
NOTE : This code is not very efficient and can be improved a lot. But will work allright if you are not running this on extremely large data.
my_list = ['4/10', '8/-', '9/2', '4/11', '-/13', '19/10', '25/-', '26/-', '4/12', '10/16']
frequency = {}; new_list = [];
for string in my_list:
x = '';
for j in string:
if j == '/':
break;
x += j;
if x.isdigit():
frequency[x] = frequency.get(x, 0) + 1;
for string in my_list:
x = '';
for j in string:
if j == '/':
break;
x += j;
if x.isdigit():
if frequency[x] > 1:
new_list.append(string);
print(new_list);
.items() is not what you think - it returns a list of key-value pairs (tuples), not sole values. You want to:
d = Counter(node)
new_list = [ k for (k,v) in d.items() if v > 1 ]
Besides, I am not sure how node is related to my_list but I think there is some additional processing you didn't show.
Update: after reading your comment clarifying the problem, I think it requires two separate counters:
first_parts = Counter([x.split('/')[0] for x in my_list])
second_parts = Counter([x.split('/')[1] for x in my_list])
first_duplicates = { k for (k,v) in first_parts.items() if v > 1 and k != '-' }
second_duplicates = { k for (k,v) in second_parts.items() if v > 1 and k != '-' }
new_list = [ e for e in my_list if
e.split('/')[0] in first_duplicates or e.split('/')[1] in second_duplicates ]
this might help : create a dict to contain the pairings and then extract the pairings that have a length more than one. defaultdict helps with aggregating data, based on the common keys.
from collections import defaultdict
d = defaultdict(list)
e = defaultdict(list)
m = [ent for ent in my_list if '-' not in ent]
for ent in m:
front, back = ent.split('/')
d[front].append(ent)
e[back].append(ent)
new_list = []
for k,v in d.items():
if len(v) > 1:
new_list.extend(v)
for k,v in e.items():
if len(v) > 1:
new_list.extend(v)
sortr = lambda x: [int(ent) for ent in x.split("/")]
from operator import itemgetter
sorted(set(new_list), key = sortr)
print(new_list)
['4/10', '4/11', '4/12', '19/10']

In python, how do I find the sum of values in a dictionary? Where each key has multiple values

My data is tab delimited and looks like this:
Name Count Sample
Dog .0001 1
Dog .00003 1
Dog .0001 2
Cat .0004 1
Cat .0002 1
Cat .0003 2
Cat .0002 2
After i define my variables unid as the first column merged with the 3rd column (ex Dog_1) and num as the Count for that line, i append each num into a dictionary under the unid (using Python 2.7), like so:
for line in K:
sp = line.split("\t")
name = sp[0]
unid = sp[3][:-2] +"_"+ sp[0]
num = int(Decimal(sp[1]))
if not dict1.has_key(unid):
dict1[unid] = []
dict1[unid].append(num)
I try to sum it with this:
dictTot = sum(dict1.values())
But i get this error message:
TypeError: unsupported operand type(s) for +: 'int' and 'list'
How can I sum these values such that I can retrieve Cat_1: .0006, Cat_2: .0005 etc?
Sorry everyone, as I know my ? is not great. But as stated by Jacob below,
"dictTot = sum(sum(value) for value in dict1.values())" sums all of the sums, but what I am looking for is to sum each group of values under each key independently so I can find out how many Cats there are in sample 1 and so on. Perhaps sum is not right for this? Sorry, as evident I am not a Python extraordinaire.
That isn't how sum works. You're trying to get an integer (or numeric value type) by "adding" a bunch of lists, so the built-in function freaks out. Try this instead:
dictTot = sum(sum(value) for value in dict1.values())
That will sum all the sums, which is what you want (I think).
EDIT
Apparently you want to sum all the values in each element of the list. For that purpose, you can use a dictionary comprehension:
dictTot = {key:sum(l_values) for key, l_values in dict1.items()}
I basically rewrote the whole thing...
K = "Dog .0001 1\n Dog .00003 1\n Dog .0001 2\n Cat .0004 1\n Cat .0002 1\n Cat .0003 2\n Cat .0002 2"
dict1 = {}
for line in K.split("\n"):
sp = line.split()
name = sp[0]
unid = "_".join([sp[0] , sp[2][-2:]])
num = float(sp[1])
if not dict1.has_key(unid):
dict1[unid] = [num,]
else :
dict1[unid].append(num)
print(dict1)
dictTot = sum([sum(x) for x in dict1.values()])
print(dictTot)
the final dict is
{'Dog_2': [0.0001],
'Dog_1': [0.0001, 3e-05],
'Cat_1': [0.0004, 0.0002],
'Cat_2': [0.0003, 0.0002]}
the sum is
0.00133
the values are lists, so you want to loop them to sum individually.
EDIT
apparently now you want "Cat_1: .0006, Cat_2: .0005 etc", so upon dict1, you can do
for key in dict1.iterkeys():
dict1[key] = sum(dict1[key])
now dict1 becomes
{'Dog_2': 0.0001,
'Dog_1': 0.00013,
'Cat_1': 0.0006,
'Cat_2': 0.0005}
In order to sum all the values, you must first join all the lists together into one iterable that sum() can process. Here are two ways to do this:
dictTot = sum(sum(dict1.values(), []))
And the slightly more verbose, but more readable:
from itertools import chain
dictTot = sum(chain.from_iterable(dict1.values()))
sum() actually takes two arguments. The second argument, start defaults to 0. Hence the error message you're getting about adding an int to list. In essence, it's doing this: 0 + [1, 2, 3] + [1, 2].... In my first example, I set the default start value to an empty list. The result is a single list. Now that I have all the values in a single list, I can sum() the result to obtain the answer.
EDIT
In response to your update:
You can do this with a generator expression:
dictTot = {key: sum(value) for key, value in dictTot.items()}
or if you are using < Python 2.7:
dictTot = dict((key, sum(value)) for key, value in dictTot.iteritems())
Answer:
dict((k,sum(v)) for k,v in dict1.iteritems())
yea, change the int(Decimal('.0001')) and use a defaultdict
+1 for a question with downvotes and then four answers that missed the oneliner answer
EDIT oops I missed that #Joel Cornett had it so props there too
This works:
d={}
for line in K:
sp = line.strip().split()
unid = sp[0]+"_"+sp[-1]
num = decimal.Decimal(sp[1])
d.setdefault(unid,[]).append(num)
print({k:sum(v) for k, v in d.items()})
Prints:
{'Dog_1': Decimal('0.00013'),
'Cat_2': Decimal('0.0005'),
'Cat_1': Decimal('0.0006'),
'Dog_2': Decimal('0.0001')}

Categories

Resources