Simple Python question with dictionaries and lists - python

The goal of the function is to make a grade adjustment based off of a dictionary and list. For instance
def adjust_grades(roster, grade_adjustment)
adjust_grades({'ann': 75, 'bob': 80}, [5, -5])
will return
{'ann': 80, 'bob': 75}
I just need a nudge in the right direction, I'm new to Python so I thought to put a nested for loop for each num in grade_adjustment but its not the right way.

Assuming Python 3.7 (ordered dicts) and the length of the adjustments match the length of the items in the dictionary, you can zip them together as follows:
for name, adjustment_amount in zip(roster, grade_adjustment):
roster[name] += adjustment_amount
>>> roster
{'ann': 80, 'bob': 75}

This is making several assumptions:
the dictionary and the list have the same length (your final code should make sure they do)
you are using a version of python in which the order of the dictionary keys is preserved (if not, you can make grade_adjustment a dictionary as well, as mentioned by other comments)
result = roster.copy()
for index, key in enumerate(roster):
result[key] += grade_adjustment[index]

You can use
def adjust_grades(roster, grade_adjustment):
for k, v in enumerate(grade_adjustment):
roster[list(roster.keys())[k]] = roster[list(roster.keys())[k]] + v
return roster
This gives output as you said {'ann': 80, 'bob': 75}

assuming 3.7 or ordered dict and equal length:
def adjust_grades(roster, grade_adjustment):
return {key:value + adjustment for (key, value), adjustment in
zip(roster.items(), grade_adjustment)}
print(adjust_grades({'ann': 75, 'bob': 80}, [5, -5]))

Related

Sort a dictionary by values in a nested dictionary

I have dictionary like so:
dic = {"first_a" : { "first_b" : {10, 2} } , "second_a" : {"second_b" : {13, 15} } [...] }
I would like to sort the nested dictionary according to the sum of first_b and second_b values.
I can't get my head around this one, could someone provide an helping hand ?
I have tried to use the sorted() function but wasn't able to find the right lambda function to use as key..
Assuming that you meant to have a dictionary like this:
data = {'a': {'b': {2, 10}}, 'c': {'d': {13, 15}}}
You can get what you want like this:
sorted(data, key =lambda k: sum(*dic[k].values()), reverse=True)
However I don't consider this very readable. I would instead do:
def get_sum(k):
vals, *_ = data[k].values()
return sum(vals)
sorted(data, key=get_sum, reverse=True)
When I'm looking at code late at night, too many parentheses == too long to figure out what's happening.
Note that I used values() because I didn't know if your inner keys were constant. If they were, life is even easier. Note this operates on and sorts the keys.

Convert a list with duplicating keys into a dictionary and sum the values for each duplicating key

I am new to Python so I do apologize that my first question might not be asked clearly to achieve the right answer.
I thought if I converted a list with duplicating keys into a dictionary then I would be able to sum the values of each duplicating key. I have tried to search on Google and Stack Overflow but I actually still can't solve this problem.
Can anybody help, please? Thank you very much in advance and I truly appreciate your help.
list1 = ["a:2", "b:5", "c:7", "a:8", "b:12"]
My expected output is:
dict = {a: 10, b: 17, c: 7}
You can try this code:
list1 = ["a:2", "b:5", "c:7", "a:8", "b:12"]
l1 = [each.split(":") for each in list1]
d1 = {}
for each in l1:
if each[0] not in d1:
d1[each[0]] = int(each[1])
else:
d1[each[0]] += int(each[1])
d1
Output: {'a': 10, 'b': 17, 'c': 7}
Explanation:
Step 1. Convert your given list to key-value pair by splitting each of the elements in your original list from : and store that in a list/tuple
Step 2. Initialize an empty dictionary
Step 3. Iterate through each key-value pair in the newly created list/tuple and store that in a dictionary. If the key doesn't exist, then add new key-value pair to dictionary or else just add the values to it's corresponding key.
A list does not have "keys" per say, rather it has elements. In your example, the elements them selves are a key value pair. To make the dictionary you want you have to do 3 things,
Parse each element into its key value pair
Handle duplicate values
Add each pair to the dictionary.
the code should look like this
list1 = ["a:2", "b:5", "c:7", "a:8", "b:12"]
dict1={}#make an empty dictionary
for element in list1:
key,value=element.split(':')#This splits your list elements into a tuple of (key,value)
if key in dict1:#check if the key is in the dictionary
dict1[key]+=int(value)#add to existing key
else:
dict1[key]=int(value)#initilize new key
print(dict1)
That code prints out
{'a': 10, 'c': 7, 'b': 17}
You could use a defaultdict, iterate over each string and add the corresponding value after splitting it to a pair (key, value).
>>> from collections import defaultdict
>>> res = defaultdict(int)
>>> for el in list1:
... k, v = el.split(':')
... res[k]+=int(v)
...
>>> res
defaultdict(<class 'int'>, {'a': 10, 'b': 17, 'c': 7})

New dict of top n values (and keys) from dictionary (Python)

I have a dictionary of names and the number of times the names appear in the phone book:
names_dict = {
'Adam': 100,
'Anne': 400,
'Britney': 321,
'George': 645,
'Joe': 200,
'John': 1010,
'Mike': 500,
'Paul': 325,
'Sarah': 150
}
Preferably without using sorted(), I want to iterate through the dictionary and create a new dictionary that has the top five names only:
def sort_top_list():
# create dict of any 5 names first
new_dict = {}
for i in names_dict.keys()[:5]:
new_dict[i] = names_dict[i]:
# Find smallest current value in new_dict
# and compare to others in names_dict
# to find bigger ones; replace smaller name in new_dict with bigger name
for k,v in address_dict.iteritems():
current_smallest = min(new_dict.itervalues())
if v > current_smallest:
# Found a bigger value; replace smaller key/ value in new_dict with larger key/ value
new_dict[k] = v
# ?? delete old key/ value pair from new_dict somehow
I seem to be able to create a new dictionary that gets a new key/ value pair whenever we iterate through names_dict and find a name/ count that is higher than what we have in new_dict. I can't figure out, though, how to remove the smaller ones from new_dict after we add the bigger ones from names_dict.
Is there a better way - without having to import special libraries or use sorted() - to iterate through a dict and create a new dict of the top N keys with the highest values?
You should use the heapq.nlargest() function to achieve this:
import heapq
from operator import itemgetter
top_names = dict(heapq.nlargest(5, names_dict.items(), key=itemgetter(1)))
This uses a more efficient algorithm (O(NlogK) for a dict of size N, and K top items) to extract the top 5 items as (key, value) tuples, which are then passed to dict() to create a new dictionary.
Demo:
>>> import heapq
>>> from operator import itemgetter
>>> names_dict = {'Adam': 100, 'Anne': 400, 'Britney': 321, 'George': 645, 'Joe': 200, 'John': 1010, 'Mike': 500, 'Paul': 325, 'Sarah': 150}
>>> dict(heapq.nlargest(5, names_dict.items(), key=itemgetter(1)))
{'John': 1010, 'George': 645, 'Mike': 500, 'Anne': 400, 'Paul': 325}
You probably want to use the collections.Counter() class instead. The Counter.most_common() method would have made your use-case trivial to solve. The implementation for that method uses heapq.nlargest() under the hood.
These are not special libraries, they are part of the Python standard library. You otherwise would have to implement a binary heap yourself to achieve this. Unless you are specifically studying this algorithm, there is little point in re-implementing your own, the Python implementation is highly optimised with an extension written in C for some critical functions).
I do not know, why you don't want to use sort and the solution is not perfect and even doesn't match your problem exactly, but I hope it can inspire you to find your own implementation. I think it was only a short example for the real Problem you have.
But as you have seen on the other answer: Normally it is better to use code, that is written before instead of do all the things yourself.
names_dict = {'Joe' : 200, 'Anne': 400, 'Mike': 500, 'John': 1010, 'Sarah': 150, 'Paul': 325, 'George' : 645, 'Adam' : 100, 'Britney': 321}
def extract_top_n(dictionary, count):
#first step: Find the topmost values
highest_values = []
for k,v in dictionary.iteritems():
print k,v, highest_values, len(highest_values)
highest_values.append(v)
l = len(highest_values)
for i in range(l-1):
print i,l
if l-i < 1:
break
if highest_values[l-i-1]>highest_values[l-i-2]:
temp = highest_values[l-i-2]
highest_values[l-i-2] = highest_values[l-i-1]
highest_values[l-i-1] = temp
highest_values = highest_values [:count]
#fill the dirctionary with all entries at least as big as the smallest of the biggest
#but pay attention: If there are more than 2 occurances of one of the top N there will be more than N entries in the dictionary
last_interesting = highest_values[len(highest_values)-1]
return_dictionary = {}
for k,v in dictionary.iteritems():
if v >= last_interesting:
return_dictionary[k] = v
return return_dictionary
print extract_top_n(names_dict,3)

Comparing the values of two dictionaries to receive their numerical difference Python

I am new to Python. I have two dictionaries which share the same keys but different values for the keys. I would like to compare the two dictionaries so that I would get the numerical difference of the values for each key. For example:
dict1 = {'hi' : 45, 'thanks' : 34, 'please' : 60}
dict2 = {'hi' : 40, 'thanks' : 46, 'please' : 50}
In other words, I would like to receive a third dictionary or a list of pairs that would show the numerical difference of the values within these two dictionaries (i.e.subtracting the values of dict1 from dict2 (or vice versa). It would thus be something like this:
dict_difference = {'hi' : 5 , 'thanks' : -12, 'please' : 10}
I know that subtracting one dictionary from another by :
dict1 = Counter({'hi' = 45, 'thanks' = 34, 'please' = 60})
dict2 = Counter({'hi' = 40, 'thanks' = 46, 'please' = 50})
dict3 = dict1-dict2 # will only return the positive values so it will give:
dict3 = {'hi'= 5, 'please' = 10} # which is NOT what I want.
I also thought of converting the dictionaries into a list of pairs (I think this is how it is called) :
dictlist = []
for key, value in dict1.iteritems():`
temp = (key, value)
dictlist.append(temp)
and therefore
print dictlist #gives:
[('hi', 45),('thanks' = 34), ('please' = 60)]
So I thought that if I can manage to convert the dictionary into the list of pairs and then to make it in the form of the key:value to be key = value I would be able to apply the subtract() method and achieve what I want.
I thought of achieving it through the def __repr__(self) as shown in https://docs.python.org/2/library/collections.html but I didn't get far.
I would be most grateful for any help. Please, if possible leave description for your code. If my approach is wrong and there is an easier way of subtracting the values of one dictionary from another please share it as well.
First, the format of your dictionaries is not correct (: and not =):
dict1 = {'hi':45, 'thanks':34, 'please':60}
dict2 = {'hi':40, 'thanks':46, 'please':50}
You can use a dictionary comprehension. You basically loop through one dictionary, check that the key is also in the second dictionary and insert the difference of the values in the output dictionary. All in one line.
dic = {key: dict1[key]-dict2[key] for key in dict1 if key in dict2}
You were on the right path with thinking about using the dictionarys' keys.
Here, I go through the first dictionary's keys, checking if they're in dictionary2. Then I do the same with dictionary2, checking for keys in dictionary1, but also ensuring that the key isn't already in the result dictionary so we don't do duplicate subtraction.
dict1 = {'hi': 45, 'thanks': 34, 'please': 60}
dict2 = {'hi': 40, 'thanks': 46, 'please': 50}
result = {}
for key in dict1.keys():
if key in dict2:
result[key] = dict1[key] - dict2[key]
for key in dict2.keys():
if key in dict1 and not key in result:
result[key] = dict1[key] - dict2[key]

Sorting with a python dictionary

I have a dictionary of "documents" in python with document ID numbers as keys and dictionaries (again) as values. These internal dictionaries each have a 'weight' key that holds a floating-point value of interest. In other words:
documents[some_id]['weight'] = ...
What I want to do is obtain a list of my document IDs sorted in descending order of the 'weight' value. I know that dictionaries are inherently unordered (and there seem to be a lot of ways to do things in Python), so what is the most painless way to go? It feels like kind of a messy situation...
I would convert the dictionary to a list of tuples and sort it based on weight (in reverse order for descending), then just remove the objects to get a list of the keys
l = documents.items()
l.sort(key=lambda x: x[1]['weight'], reverse=True)
result = [d[0] for d in l]
I took the approach that you might want the keys as well as the rest of the object:
# Build a random dictionary
from random import randint
ds = {} # A |D|ata |S|tructure
for i in range(20,1,-1):
ds[i]={'weight':randint(0,100)}
sortedDS = sorted(ds.keys(),key=lambda x:ds[x]['weight'])
for i in sortedDS :
print i,ds[i]['weight']
sorted() is a python built in that takes a list and returns it sorted (obviously), however it can take a key value that it uses to determine the rank of each object. In the above case it uses the 'weight' value as the key to sort on.
The advantage of this over Ameers answer is that it returns the order of keys rather than the items. Its an extra step, but it means you can refer back into the original data structure
This seems to work for me. The inspiration for it came from OrderedDict and question #9001509
from collections import OrderedDict
d = {
14: {'weight': 90},
12: {'weight': 100},
13: {'weight': 101},
15: {'weight': 5}
}
sorted_dict = OrderedDict(sorted(d.items(), key=lambda rec: rec[1].get('weight')))
print sorted_dict

Categories

Resources