Most efficient method to find values in nested dict - python

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())

Related

List with string code names to numeric codes in python3

I am very new to Python. I have this list called 'prediction' with results from an LDA classification problem. The elements in 'prediction' are string, which I want to convert to numeric values. I am doing it by brute-force like:
aux2 = [0]*len(prediction)
i = 0
for k in prediction:
if k == 'ALA':
aux2[i] = 1
elif k == 'ARG':
aux2[i] = 2
elif k == 'ASN':
aux2[i] = 3
elif k == 'ASP':
aux2[i] = 4
...
elif k == 'VAL':
aux2[i] = 18
i = i+1
But I am sure there is a better way to do it. Please put me out of my ignorance!
You could use a dictionary for this!
Dictionaries use keys to refer to certain values; This means you can assign each string an integer value according to your need and use it as so:
translation_dict = {
'ALA': 1,
'ARG': 2,
'ASN': 3,
'ASP': 4,
...
'VAL': 18
}
aux2 = [0]*len(prediction)
for i, k in enumerate(prediction):
aux2[i] = translation_dict[k]
You'll also notices I swapped out your counter (i) with an enumerate function. This function takes any iterator and returns a new iterator which gives you the index in addition to the value, thus saving you from manually incrementing i.

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']

iterate through a dictionary inside a dictionary in 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)

Python simple for loop issue

Currently learning python. Normally a C++ guy.
if wallpaper == "Y":
charge = (70)
print ("You would be charged £70")
wallpaperList.append(charge)
elif wallpaper == "N" :
charge = (0)
else:
wallPaper ()
surfaceArea
totalPapers = 0
for item in range (len(wallpaperList)):
totalPapers += wallpaperList[item]
I am trying do a for loop for the if statement.
In c++ this will just be a simple
for (I=0; i<pRooms; i++){
}
I am trying to add the above code in a for loop but I seem to fail.
Thanks
Python loops iterate over everything in the iterable:
for item in wallpaperList:
totalPapers += item
In modern C++, this is analogous to:
std::vector<unsigned int> wallpaperList;
// ...
for(auto item: wallpaperList) {
totalPapers += item
}
You could also just use the sum function:
cost = sum(wallpaperList)
If the charge is 70 every time, why not just do multiplication?
while wallPaper == 'Y':
# ...
# Another satisfied customer!
i += 1
cost = i * 70
For the exact equivalent of your for loop, use range:
for (i=0; i<pRooms; i++){ # C, C++
}
for i in range(pRooms): # Python
...
Both loops iterate over the values 0 to pRooms-1. But python gives you other options. You can iterate over the elements of the list without using an index:
for room in listOfRooms:
if room.wallpaper == "Y":
...
List comprehensions are also nice. If you don't care about the print calls in your code, you could compute the cost in one line with something like this:
totalPapers = sum(70 for room in listOfRooms if room.wallpaper == "Y")

Categories

Resources