My Ordered Dict is not working as I expected - python

So basically I have this code:
from collections import OrderedDict as OD
person = OD({})
for num in range(10):
person[num] = float(input())
tall = max(person.values())
short = min(person.values())
key_tall = max(person.keys())
key_short = min(person.keys())
print(f'The shortest person is the person number {key_short} who is {short}meters tall')
print(f'The tallest person is the person number {key_tall} who is {tall}meters tall')
And in theory when I put 10 people on my dictionary, being the first number 1, going all the way to 9, and the last one being 0, the output should be:
The shortest person is the person number 9 who is 0.0m meters tall
The tallest person is the person number 8 who is 9.0m meters tall
But in fact it prints:
The shortest person is the person number 0 who is 0.0m meters tall
The tallest person is the person number 9 who is 9.0m meters tall
And for some reason when the values of my dictionary go to 1 all the way to 10, it works fine.
Any ideas on why this is happening and how to fix it?

key_tall = max(person.keys())
key_short = min(person.keys())
Your keys are the integers 0..9 so it's expected that you'll get 9 and 0 for these two values, since you're asking for the min/max key without regard to the values.
You seem to be after the key of the person that has the highest/lowest value, but that's not what that code will give you.
If you're after the indexes of the items with the largest values, you can do something like:
indexes_tall = [idx for idx in range(len(person)) if person[idx] == max(person.keys())]
This will give you a list of the indexes matching the highest value, which you can then process as you see fit. As one example:
from collections import OrderedDict as OD
person = OD({})
for num in range(10):
person[num] = float((num + 1) % 10) # effectively your input
tall = max(person.values())
short = min(person.values())
keys_tall = [str(idx + 1) for idx in range(len(person)) if person[idx] == max(person.keys())]
keys_short = [str(idx + 1) for idx in range(len(person)) if person[idx] == min(person.keys())]
print(f'The shortest height of {short}m is held by: {" ".join(keys_short)}')
print(f'The tallest height of {tall}m is held by: {" ".join(keys_tall)}')
will give you:
The shortest height of 0.0m is held by: 10
The tallest height of 9.0m is held by: 9

Related

Paradox python algorithm

I am trying to solve a version of the birthday paradox question where I have a probability of 0.5 but I need to find the number of people n where at least 4 have their birthdays within a week of each other.
I have written code that is able to simulate where 2 people have their birthdays on the same day.
import numpy
import matplotlib.pylab as plt
no_of_simulations = 1000
milestone_probabilities = [50, 75, 90, 99]
milestone_current = 0
def birthday_paradox(no_of_people, simulations):
global milestone_probabilities, milestone_current
same_birthday_four_people = 0
#We assume that there are 365 days in all years.
for sim in range(simulations):
birthdays = numpy.random.choice(365, no_of_people, replace=True)
unique_birthdays = set(birthdays)
if len(unique_birthdays) < no_of_people:
same_birthday_four_people += 1
success_fraction = same_birthday_four_people/simulations
if milestone_current < len(milestone_probabilities) and success_fraction*100 > milestone_probabilities[milestone_current]:
print("P(Four people sharing birthday in a room with " + str(no_of_people) + " people) = " + str(success_fraction))
milestone_current += 1
return success_fraction
def main():
day = []
success = []
for i in range(1, 366): #Executing for all possible cases where can have unique birthdays, i.e. from 1 person to a maximum of 365 people in a room
day.append(i)
success.append(birthday_paradox(i, no_of_simulations))
plt.plot(day, success)
plt.show()
main()
I am looking to modify the code to look for sets of 4 instead of 2 and then calculate the difference between them to be less than equal to 7 in order to meet the question.
Am I going down the right path or should I approach the question differently?
The key part of your algorithm is in these lines:
unique_birthdays = set(birthdays)
if len(unique_birthdays) < no_of_people:
same_birthday_four_people += 1
Comparing the number of unique birthdays to the number of people did the work when you tested if two different people had the same birthday, but It wont do for your new test.
Define a new function that will receive the birthday array and return True or False after checking if indeed 4 different people had the a birthday in a range of 7 days:
def four_birthdays_same_week(birthdays):
# fill this function code
def birthday_paradox(no_of_people, simulations):
...
(this function can be defined outside the birthday_paradox function)
Then switch this code:
if len(unique_birthdays) < no_of_people:
same_birthday_four_people += 1
into:
if four_birthdays_same_week(birthdays):
same_birthday_four_people += 1
Regarding the algorithm for checking if there 4 different birthday on the same week: a basic idea would be to sort the array of birthdays, then for every group of 4 birthdays check if the day range between them is equal or lower to 7:
if it is, the function can immediately return True.
(I am sure this algorithm can be vastly improved.)
If after scanning the whole array we didn't return True, the function can return False.

Given a street with lamps, finding minimum cost to light entire street [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Here's an exercise I'm struggling with.
A street has n lamps, i-th lamp is in position i.
Initially all lamps are switched off. For the i-th lamp you have 3 options:
Leave it switched Off and pay nothing.
Switch it to Mode 1 and pay cost1i. The i-th lamp will light position i.
Switch it to Mode 2 and pay cost2i. The i-th lamp will light the position i and leftRangei more positions to the left and rightRangei more positions to the right. For example, if i = 5, and leftRangei = 3 and _rightRangei = 2, then, switching the light to mode 2 will light positions 2, 3, 4, 5, 6 and 7
I need to find the minimum total cost to light all lamps.
cost1, cost2, leftRange and rightRange are all arrays.
This is a basic exercise in dynamic programming.
I suggest you first transform the arrays into a set of (interval, cost) pairs. Then ask yourself:
What subset of intervals can I use to cover the entire street at the lowest cost?
Reformulate this question into something more recursion friendly as follows:
What subset of intervals can I use to cover the street up until index i at the lowest cost?
This question can be answered as follows:
The cheapest way to cover the street up until index i is to use a light that covers i PLUS the cheapest way to cover the street up until the left range of that light.
The PLUS part can be answered by looking at previously computed costs, since that part is stricly less than i
Which light to use to cover i is determined by iterating over all lights that cover i and picking the cheapest one.
When you have this recursive solution in place, simply answer the questions in the following order:
What subset of intervals can I use to cover the street up until index 1 at the lowest cost? (base case)
What subset of intervals can I use to cover the street up until index 2 at the lowest cost? (computation involves looking at previous answers)
...
What subset of intervals can I use to cover the street up until index n at the lowest cost? (computation involves looking at previous answers)
Here's a first stab at it:
# Sample data
n = 5
cost1 = [ 10, 20, 10, 5, 3 ]
cost2 = [ 15, 25, 10, 10, 30 ]
leftRange = [ 0, 1, 0, 1, 2 ]
rightRange = [ 2, 0, 1, 1, 0 ]
class LightRange:
def __init__(self, light, mode, left, right, cost):
self.light = light
self.mode = mode
self.left = left
self.right = right
self.cost = cost
def doesCover(self, i):
return self.left <= i and i <= self.right
# Transform input data into a set of LightRanges
ranges = []
for i in range(n):
ranges.append(LightRange(i, 1, i, i, cost1[i]))
ranges.append(LightRange(i, 2, i - leftRange[i], i + rightRange[i], cost2[i]))
# For convenience: Create an index telling us what ranges covers index i
rangesCoveringI = []
for i in range(n):
rangesCoveringI.append([])
for r in ranges:
if r.doesCover(i):
rangesCoveringI[i].append(r)
# Declare two variables holding our solution:
# costToCoverI[i] = the lowest cost for lighting up the street from 0 to i
costToCoverI = []
# rangeUsedToCoverI[i] = range used for covering i when lighting up the street from 0 to i
rangeUsedToCoverI = []
# Populate the solution variables going from left to right on the street
for i in range(n):
# Walk through ranges covering i and determine the cheapest one to use
bestCostToCoverI = None
bestRangeToCoverI = None
for r in rangesCoveringI[i]:
# Compute cost associated with using this range
costThisRange = r.cost
costLeftOfThisRange = 0 if r.left <= 0 else costToCoverI[r.left - 1]
cost = costThisRange + costLeftOfThisRange
# Cheapest so far?
if bestCostToCoverI is None or cost < bestCostToCoverI:
bestCostToCoverI = cost
bestRangeToCoverI = r
costToCoverI.append(bestCostToCoverI)
rangeUsedToCoverI.append(bestRangeToCoverI)
# Final solution: costToCoverI[n - 1] = the lowest cost for lighting up the street from 0 to n
print(f"Total cost: {costToCoverI[n - 1]}")
# Backtrack to figure out final mode selection
i = n - 1
while i > 0:
r = rangeUsedToCoverI[i]
print(f"{r.light} set to mode {r.mode}")
i = r.left - 1
Output:
Total cost: 23
4 set to mode 1
3 set to mode 1
0 set to mode 2
N.B.: Untested code.
Try it out, and try to understand each step.
Debug any issues you find.
Ask follow-up questions in the comments if there's something you don't understand.

PYTHON - "Love for Mathematics"

I just finished a challenge on Dcoder ("Love for Mathematics") using Python. I failed two test-cases, but got one right. I used somewhat of a lower level of Python for the same as I haven't explored more yet, so I'm sorry if it looks a bit too basic.The Challenge reads:
Students of Dcoder school love Mathematics. They love to read a variety of Mathematics books. To make sure they remain happy, their Mathematics teacher decided to get more books for them.
A student would become happy if there are at least X Mathematics books in the class and not more than Y books because they know "All work and no play makes Jack a dull boy".The teacher wants to buy a minimum number of books to make the maximum number of students happy.
The Input
The first line of input contains an integer N indicating the number of students in the class. This is followed up by N lines where every line contains two integers X and Y respectively.
#Sample Input
5
3 6
1 6
7 11
2 15
5 8
The Output
Output two space-separated integers that denote the minimum number of mathematics books required and the maximum number of happy students.
Explanation: The teacher could buy 5 books and keep student 1, 2, 4 and 5 happy.
#Sample Output
5 4
Constraints:
1 <= N <= 10000
1 <= X, Y <= 10^9
My code:
n = int(input())
l = []
mi = []
ma = []
for i in range(n):
x, y = input().split()
mi.append(int(x))
ma.append(int(y))
if i == 0:
h=ma[0]
else:
if ma[i]>h:
h=ma[i]
for i in range(h):
c = 0
for j in range(len(mi)):
if ma[j]>=i and mi[j]<=i:
c+=1
l.append(c)
great = max(l)
for i in range(1,len(l)+1):
if l[i]==great:
print(i,l[i])
break
My Approach:
I first assigned the two minimum and maximum variables to two different lists - one containing the minimum values, and the other, the maximum. Then I created a loop that processes all numbers from 0 to the maximum possible value of the list containing maximum values and increasing the count for each no. by 1 every time it lies within the favorable range of students.
In this specific case, I got that count list to be (for the above given input):
[1,2,3,3,4,4,3,3,2 ...] and so on. So I could finalize that 4 would be the maximum no. of students and that the first index of 4 in the list would be the minimum no. of textbooks required.
But only 1 test-case worked and two failed. I would really appreciate it if anyone could help me out here.
Thank You.
This problem is alike minimum platform problem.
In that, you need to sort the min and max maths books array in ascending order respectively. Try to understand the problem from the above link (platform problem) then this will be a piece of cake.
Here is your solution:
n = int(input())
min_books = []
max_books = []
for i in range(n):
x, y = input().split()
min_books.append(int(x))
max_books.append(int(y))
min_books.sort()
max_books.sort()
happy_st_result = 1
happy_st = 1
books_needed = min_books[0]
i = 1
j = 0
while (i < n and j < n):
if (min_books[i] <= max_books[j]):
happy_st+= 1
i+= 1
elif (min_books[i] > max_books[j]):
happy_st-= 1
j+= 1
if happy_st > happy_st_result:
happy_st_result = happy_st
books_needed = min_books[i-1]
print(books_needed, happy_st_result)
Try this, and let me know if you need any clarification.
#Vinay Gupta's logic and explanation is correct. If you think on those lines, the answer should become immediately clear to you.
I have implemented the same logic in my code below, except using fewer lines and cool in-built python functions.
# python 3.7.1
import itertools
d = {}
for _ in range(int(input())):
x, y = map(int, input().strip().split())
d.setdefault(x, [0, 0])[0] += 1
d.setdefault(y, [0, 0])[1] += 1
a = list(sorted(d.items(), key=lambda x: x[0]))
vals = list(itertools.accumulate(list(map(lambda x: x[1][0] - x[1][1], a))))
print(a[vals.index(max(vals))][0], max(vals))
The above answer got accepted in Dcoder too.

How to prevent 36k x 36k x 36k permutations to be calculated

I have a nice planning exercise, that I just can't get my head around (except for brute force, which is too big to handle). We are organizing a golf trip for 12 persons. We play 4 days of golf. With 3 flights every day. (so 12 flights in total).
We want to:
maximize the number of unique players that play each other in a flight,
but also want to minimize the number of double occurences (2 players playing each other more than once).
Since with 12 players and 4 players per flight I can roughly create 36k player combinations per flight per day, it becomes pretty compute intense. Is there any smarter way to solve this? My gut feeling says fibonacci can help out, but not sure how exactly.
This is the code I have so far:
import random
import itertools
import pandas as pd
def make_player_combi(day):
player_combis = []
for flight in day:
#print flight
for c in itertools.combinations(flight,2):
combi = list(sorted(c))
player_combis.append('-'.join(combi))
return player_combis
def make_score(a,b,c):
df = pd.DataFrame(a + b + c,columns=['player_combi'])['player_combi']
combi_counts = df.value_counts()
pairs_playing = len(combi_counts)
double_plays = combi_counts.value_counts().sort_index()
return pairs_playing, double_plays
players = ['A','B','C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','K','L']
available_players = players[:]
n = 0
combinations_per_day = []
for players_in_flight_1 in itertools.combinations(players,4):
available_players_flight_1 = players[:]
available_players_flight_2 = players[:]
available_players_flight_3 = players[:]
for player in players_in_flight_1:
# players in flight1 can no longer be used in flight 2 or 3
available_players_flight_2.remove(player)
available_players_flight_3.remove(player)
for players_in_flight_2 in itertools.combinations(available_players_flight_2,4):
players_in_flight_3 = available_players_flight_3[:]
for player in players_in_flight_2:
players_in_flight_3.remove(player)
n = n + 1
print str(n), players_in_flight_1,players_in_flight_2,tuple(players_in_flight_3)
combinations_per_day.append([players_in_flight_1,players_in_flight_2,tuple(players_in_flight_3)])
n_max = 100 # limit to 100 entries max per day to save calculations
winning_list = []
max_score = 0
for day_1 in range(0,len(combinations_per_day[0:n_max])):
print day_1
for day_2 in range(0,len(combinations_per_day[0:n_max])):
for day_3 in range(0,len(combinations_per_day[0:n_max])):
a = make_player_combi(combinations_per_day[day_1])
b = make_player_combi(combinations_per_day[day_2])
x,y = make_score(a,b,c)
if x >= max_score:
max_score = x
my_result = {'pairs_playing' : x,
'double_plays' : y,
'max_day_1' : day_1,
'max_day_2' : day_2,
'max_day_3' : day_3
}
winning_list.append(my_result)
I chose the suboptimal ( but good enough) solution by running 5 mio samples and taking the lowest outcome... Thanks all for thinking along
You can brute-force this by eliminating symmetries. Let's call the 12 players a,b,c,d,e,f,g,h,i,j,k,l, write a flight with 4 players concatenated together: degj, and a day's schedule with the three flights: eg. abcd-efgh-ijkl.
The first day's flights are arbitrary: say the 3 flights are abcd-efgh-ijkl.
On the second and third day, you have fewer than (12 choose 4) * (8 choose 4) possibilities, because that counts each distinct schedule 6 times. For example, abcd-efgh-ijkl, efgh-abcd-ijkl and ijkl-efgh-abcd are all counted as separate, but they are essentially the same. In fact, you have (12 choose 4) * (8 choose 4) / 6 = 5775 different schedules.
Overall, this gives you 5775 * 5775 = 33350625, a manageable 33 million to check.
We can do a little better: we might as well assume that day 2 and day 3 schedules are different, and not count schedules that are the same but day 2 and day 3's are swapped over. This gives us another factor of very almost 2.
Here's code that does all that:
import itertools
import collections
# schedules generates all possible schedules for a given day, up
# to symmetry.
def schedules(players):
for c in itertools.combinations(players, 4):
for d in itertools.combinations(players, 4):
if set(c) & set(d):
continue
e = set(players) - set(c) - set(d)
sc = ''.join(sorted(c))
sd = ''.join(sorted(d))
se = ''.join(sorted(e))
if sc < sd < se:
yield sc, sd, se
# all_schedules generates all possible (different up to symmetry) schedules for
# the three days.
def all_schedules(players):
s = list(schedules(players))
d1 = s[0]
for d2, d3 in itertools.combinations(s, 2):
yield d1, d2, d3
# pcount returns a Counter that records how often each pair
# of players play each other.
def pcount(*days):
players = collections.Counter()
for d in days:
for flight in d:
for p1, p2 in itertools.combinations(flight, 2):
players[p1+p2] += 1
return players
def score(*days):
p = pcount(*days)
return len(p), sum(-1 for v in p.itervalues() if v > 1)
best = None
for days in all_schedules('abcdefghijkl'):
s = score(*days)
if s > best:
best = s
print days, s
It still takes some time to run (about 10-15 minutes on my computer), and produces this as the last line of output:
abcd-efgh-ijkl abei-cfgj-dhkl abhj-cekl-dfgi (48, -3)
That means there's 48 unique pairings over the three days, and there's 3 pairs who play each other more than once (ab, fg and kl).
Note that each of the three pairs who play each other more than once play each other on every day. That's unfortunate, and probably means you need to tweak your idea of how to score schedules. For example, excluding schedules where the same pair plays more than twice, and taking the soft-min of the number of players each player sees, gives this solution:
abcd-efgh-ijkl abei-cfgj-dhkl acfk-begl-dhij
This has 45 unique pairings, and 9 pairs that play each other more than once. But every player meets at least 7 different players and might be preferable in practice to the "optimal" solution above.

I cant get my code to work. it keeps saying: IndexError: List index out of range

My code is using the lengths of lists to try and find a percentage of how many scores are over an entered number.It all makes sense but I think some of the code needs some editing because it comes up with that error code.How can I fix it???
Here is the code:
result = [("bob",7),("jeff",2),("harold",3)]
score = [7,2,3]
lower = []
higher = []
index2 = len(score)
indexy = int(index2)
index1 = 0
chosen = int(input("the number of marks you want the percentage to be displayed higher than:"))
for counter in score[indexy]:
if score[index1] >= chosen:
higher.append(score[index1])
else:
lower.append(score[index1])
index1 = index1 + 1
original = indexy
new = len(higher)
decrease = int(original) - int(new)
finished1 = decrease/original
finished = finished1 * 100
finishedlow = original - finished
print(finished,"% of the students got over",chosen,"marks")
print(finishedlow,"% of the students got under",chosen,"marks")
Just notice one thing:
>>>score = [7,2,3]
>>>len(score) = 3
but ,index of list start counting from 0, so
>>>score[3]
IndexError: list index out of range
fix your row 12 to:
...
for counter in score:
if counter >= chosen:
...
if you really want to get the index and use them:
....
for index, number in enumerate(score):
if score[index] >= chosen:
......
Your mistake is in Line 9: for counter in score[indexy]:
counter should iterate through a list not through an int and even that you are referring to a value that is out of index range of your list:
1 - Remember indexing should be from 0 to (len(list)-0).
2 - You cannot iterate through a fixed value of int.
So, you should change Line 9 to :
for counter in score
But I'm not sure of the result you will get from your code, you need to check out your code logic.
There is a lot to optimize in your code.
index2 is an int, so no need to convert it to indexy. Indizes in Python are counted from 0, so the highest index is len(list)-1.
You have a counter, so why use index1 in for-loop? You cannot iterate over a number score[indexy].
results = [("bob",7),("jeff",2),("harold",3)]
chosen = int(input("the number of marks you want the percentage to be displayed higher than:"))
higher = sum(score >= chosen for name, score in results)
finished = higher / len(results)
finishedlow = 1 - finished
print("{0:.0%} of the students got over {1} marks".format(finished, chosen))
print("{0:.0%} of the students got under {1} marks".format(finishedlow, chosen))

Categories