Python max on potential same values - python

I have a problem with the max() function of python.
Here's my situation :
results = {'left' : leftKeyCounter, 'right' : rightKeyCounter, 'front' : frontKeyCounter, 'back' : backKeyCounter}
finalScore = max(results, key=results.get)
print(finalScore, 'wins')
The problem I have is to make if conditions on what's happening with my results. Let's say, I have
results = {'left' : 1, 'right' : 1, 'front' : 1, 'back': 0}
The fact that he will return 'front wins' on this is completely random, and I need to filter over that result. (or before?)
So that if it's a draw between the 2 highest results, that he cancels it (for example)
What could be the easiest way to make that possible ? I looked into the "counter" but that doesn't achieve what I intend to do here, as my numbers are already packed and I just need to compare 4 values, without any tie between the 2 highests value.
Thanks a lot ! :-)

With one pass over the dictionary you can figure out the correct result. Reverse the keys with the values and keep a track of the highest score. If there is more than one items for the highest score, you can return a custom message.
In reversing, you can't simply do {value: key for key, value in results.items()}, because if two values are the same, they will overwrite the previous one. So you have to keep the results in a list. Credits to chepner for scores.setdefault(). He also suggested that the same can be achieved with collections.defaultdict().
def calculate_winner(d):
scores = {}
high_score = 0
for key, value in d.items():
scores.setdefault(value, []).append(key)
if value > high_score:
high_score = value
results = scores[high_score]
if len(results) == 1:
return results[0]
else:
return 'TIE', results
Example:
>>> calculate_winner(results)
('TIE', ['front', 'right', 'left'])
Edit: If you have a small dictionary, you can achieve the same result with fewer lines of code by doing two passes: one to find the max score and one to filter out the winners.
def calcaluate_winner(d):
max_value = max(d.values())
winners = [key for key in d if d[key] == max_value]
if len(winners) == 1:
return winners[0]
else:
return 'TIE', winners

Related

Python function to find ALL second lowest SCORERS in a Dictionary with minimal possible order of time (O(n))

Hi I want to write a python function to find all lowest scorers in dictionary with time complexity of o(n).
The function should handle 2nd lowest value in any index of dictionary including the first k,v pairs.
function should handle duplicate lowest scores too.
Testcase:
second_lowest_scorers({"hri":6.2,"dav":1.1,"asv":1.1,"wrs":12.3,"dup":6.2,"awe":43.2,"asw":22.2,"asd":6.2})
expected output:
['asd', 'dup', 'hri'] (optional: sorted by name)
Explanation asv and dav scored 1.1 which is lowest score. asd,dup,hri scored next lowest.
I have so far solved it using multiple loops.
def lowest_scores(names_scores):
lowest_score=min(names_scores.values())
lowscorers=[]
low_scorer_dict = { k : v for k,v in names_scores.items() if v != lowest_score}
second_lowest_score = min(low_scorer_dict.values())
for k,v in low_scorer_dict.items():
if v == second_lowest_score:
lowscorers.append(k)
return sorted(lowscorers)
Dont want to use external functions like to solve algorithmic way possible
O(N) solution
data = {"hri":6.2,"dav":1.1,"asv":1.1,"wrs":12.3,"dup":6.2,"awe":43.2,"asw":22.2,"asd":6.2}
vals = set(data.values()) # create set so we don't get duplicates
vals.remove(min(vals)) # remove the most minimum
minVal = min(vals) # this is the second minimum
for k,v in data.items():
if v == minVal :
print(k) # where value is second minimum
hri
dup
asd

Python- How to compare new value with previous value on for-loop?

My function needs to find the character with the highest speed in a dictionary. Character name is the key and value is a tuple of statistics. Speed is index 6 of the value tuple. How do I compare the previous highest speed to the current value to see if it is higher? Once I get the speed, how can I take that character's types (index 1 and 2 in value tuple,) and return them as a list?
Example Data:
d={'spongebob':(1,'sponge','aquatic',4,5,6,70,6), 'patrick':(1,'star','fish',4,5,6,100,1)}
Patrick has the highest speed(100) and his types are star and fish. Should return [star,fish]
Here is my current code which doesn't work since I don't know how to compare previous and current:
def fastest_type(db):
l=[]
previous=0
new=0
make_list=[[k,v] for k,v in db.items()]
for key,value in db.items():
speed=value[6]
return l_types.sort()
The sorted function can do this quite easily:
Code:
from operator import itemgetter
def fastest_type(db):
fastest = sorted(db.values(), reverse=True, key=itemgetter(6))[0]
return fastest[1], fastest[2]
This code sorts by key 6, in reverse order so that the largest is first, and then set fastest to the first element of the sort. Then it simply returns the two desired fields from fastest.
Test Code:
d = {
'spongebob':(1,'sponge','aquatic',4,5,6,70,6),
'patrick':(1,'star','fish',4,5,6,100,1)
}
print(fastest_type(d))
Results:
('star', 'fish')
If I understood what you meant.
def fastest_type(db):
speed = 0
new = []
for key,value in db.items():
if speed < value[6]:
speed = value[6]
new = value[1:3]
return list(new) # return list instead of tuple

Determining Key with Most Values

dictionary = {"key1": ["Item1", "Item2"], "key2": ["Item3", "Item4"]}
Working with the above dictionary, trying to iterate through it and return the key with most values.
I was trying this:
def most_values(a):
return max(a, key=a.get)
Which isn't bad though it's going to return whatever key it checks first. Next I tried:
def most_values(a):
count = 0
high = ""
for t in a:
if len(a[t]) > count:
count += 1
high = t
return high
But it does the same and will return whatever key it iterated through first. It's also not a very elegant looking solution.
What's the most Pythonic way of going about this?
The problem with:
return max(a, key=a.get)
is that here the key will return the actual list and in Python lists are compared lexicographically, so not by length (there are things to say for both ways to compare lists, but they decided to sort lexicographically). You can however easily modify this with:
def most_values(a):
return max(a, key=lambda x:len(a[x]))
This is probably the most Pythonic way since it is declarative (you do not have to think how the maximum is calculated), elegantly, readable and has no side effects.
The problem with your second approach is that you should set count to the new len(a[t]), not increment it. So you can fix it like:
def most_values(a):
count = -1
high = None
for key,val in a.items():
if len(val) > count:
count = len(val) # semantical error in your code
high = key
return high
how about this:
sorted(dictionary.iteritems(), key=lambda x:len(x[1]), reverse=True)[0][0]
sorted() sorts stuff. dictionary.iteritems() is an iterator for key:value pairs in the dict. key will receive such a pair and use the 2nd item in it (the value) as the thing its comparing. reverse=True will make it sort from big to small. the first [0] will return the "biggest" key value pair and the second [0] will return the key
or go with Willem Van Onsem's idea because its much cleaner

A simpler way to run a function on dictionary values w/o losing the association to keys?

I'd like to run a function on all the values in a dictionary. To make things more complicated, the exact transformation each value goes through is not independent, but contingent on the transformations other values before it went through.
Here's a simple function, defined on a list, to show what I mean:
def new_list_generator(mylist):
number_of_iterations = 0
new_list = []
for n in mylist:
if number_of_iterations%2 == 0:
new_list.append(n**1.25)
number_of_iterations += 1
else:
new_list.append(n**0.5)
number_of_iterations += 1
return new_list
You can see that the power we employ on each value depends on the the history - how many values were modified before it.
Now, that's the function defined for a list. What happens when I want to modify a dictionary's values without disassociating keys and values (that is, I don't want to simply create a list of all the values and feed that list to the function)?
The best solution I could think of (and make it work) was the following cumbersome solution:
step 1: transform the dictionary to a list of tuples. i.e. [(value1,key1), (value2,key2),...]
step 2: run a modified function on that list.
step 3: convert the list back to a dictionary with dict().
That is:
some_dict = {"Graham": 13, "Eric": 19, "Terry G": 7, "Terry J":11, "John": 15, "Michael": 7}
dict_to_tuples = some_dict.items()
def new_list_generator1(mylist): # notice it's a new function
number_of_iterations = 0
new_list = []
for n in mylist:
if number_of_iterations%2 == 0:
new_list.append((n[0],n[1]**1.25)) # <== new
number_of_iterations += 1
else:
new_list.append((n[0],n[1]**0.5)) # <== new
number_of_iterations += 1
return new_list
tups = new_list_generator1(dict_to_tuples)
print dict(tups)
I was wondering if there's a less cumbersome way to do that, hopefully without having to modify the original list. I googled around and couldn't find anything informative on Stackoverflow or elsewhere (where the function employed on dict values depends on history).
Thanks for your help.
Just loop through the keys and modify the values directly.
some_dict = {"Graham": 13, "Eric": 19, "Terry G": 7, "Terry J":11, "John": 15, "Michael": 7}
def new_list_generator1(mydict): # notice it's a new function
number_of_iterations = 0
for key in mydict:
if number_of_iterations%2 == 0:
mydict[key] = mydict[key]**1.25
else:
mydict[key] = mydict[key]**0.5
number_of_iterations += 1
return mydict
print new_list_generator1(some_dict)
As #kroolik correctly pointed out below, this can be simplified further with enumerate at least for the current example.
def new_list_generator1(mydict): # notice it's a new function
for i, key in enumerate(mydict):
if i%2 == 0: mydict[key] = mydict[key]**1.25
else: mydict[key] = mydict[key]**0.5
return mydict
As pointed out in the comments, it's quite strange to process values of a dict in terms of the iteration order, because that order is not guaranteed, so it could lead to different values every time you apply the function. That being said, if the only parameter that you take into account when processing is the iteration step, you could simply use a dict comprehension:
{key: some_dict[key]**([1.25, 0.5][i % 2]) for i, key in enumerate(some_dict)}
Or more generally
def process_value(value, iteration_step):
# new_value = ...
return new_value
{key: process_value(some_dict[key], i) for i, key in enumerate(some_dict)}

Key to maxima of dictionary in python

I have a dictionary, "scores", of integers and I want to find the key(s) of the highest value. I used this code:
key = max(scores, key=scores.get)
however, this only gives back one key. How does this deal with ties in highest value? I only get one number back. Which is it in the case of a tie? How can I get all the keys to the highest value?
Thanks for your help.
You could run the following, for example:
max_value = max(scores.values())
keys = [ i for (i,v) in scores.iteritems() if v == max_value ]
"keys" would now hold all the keys which correspond to the maximum value.
scores = dict(a=1,b=2,c=3,d=4,e=5,f=5)
maxscr = max(scores.values())
maxscrs = [scr for scr in scores if scores[scr]== maxscr]
gives:
['e','f']
max_value = max(scores, key=scores.get)
keys = [score for score in scores if scores[score] == max_value]
The max function returns one value. You could use something like this:
key = max(scores, key=scores.get)
keys = [k for k in scores if scores[k] == scores[key]]
Edit: fixed

Categories