How to randomly pick key from dict and change value? - python

I want to randomly select an animal and if there is no value 0 then decrease the value by 1.
I want to repeat the action twice.
Try:
animals = {
"pets": {"dog": 2, "cat": 1, "mouse": 0}}
a = random.choice(list(animals["pets"]))
but this only displays the name of the animal.
I would like to get a result like this:
dog 1, cat 0, mouse 0
How to do it?
Thank you and best regards.

I'm assuming you want to choose a random animal and then decrease the value associated with that animal each time it is chosen. I will also assume you don't want these values to go below 0. This can be done as follows:
import random
animals = {
"pets": {"dog": 2, "cat": 1, "mouse": 0}}
# I wasn't sure what else to name this
def KillPet(animals):
pets = animals["pets"]
pet = random.choice(list(pets.keys()))
if pets[pet] > 0:
pets[pet] -= 1
return True
# A pet was successfully removed
# A pet was not removed
return False
numberOfPetsRemoved = 0
# Remove 2 pets
while numberOfPetsRemoved < 2:
success = KillPet(animals)
if success:
numberOfPetsRemoved += 1
print(animals)

Related

How to find a certain amount of same adjacent elements in a row of a nested list

There is a hotel e.g. of size 7x5. I need to create a function where
a number is given as parameter for finding the amount of consecutive empty rooms
returns the number of floor and room number in that.
(depicted below: 0 is empty room and 1 is full)
e.g.:
if the parameter is 1, output will be
"floor no: 5, start from room no: 1"
if the parameter is 2, output will be
"floor no: 5, start from room no: 3"
if the parameter is 3, output will be
"floor no: 5, start from room no: 3"
if the parameter is 4, output will be
"floor no: 4, start from room no: 4"
if the parameter is 5, output will be
"floor no: 2, start from room no: 1"
if the parameter is 6 (or 7), output will be
"floor no: 1, start from room no: 1"
if the parameter is > 7, output will be
"not possible to find in one floor"
preferably without using itertools.grupby.
My try:
def adjacent_rooms (amount):
nested_list_temp = [[0]*7]*5
nested_list = [list(i) for i in nested_list_temp]
nested_list [1][5] = 1
nested_list [2][3] = 1
nested_list [2][4] = 1
nested_list [3][2] = 1
nested_list [4][1] = 1
nested_list [4][5] = 1
# [[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0]]
try:
for i in range(len(nested_list), 0, -1):
for j in range(len(nested_list[0])):
if nested_list[i-1][j] == 0:
count += 1
if count == amount:
return (i, j-amount+2)
else:
count = 0
except:
return "not possible to find in one floor"
Any effective hints or suggestions will be highly appreciated.
Use narrow try-except conditions. The first problem is your all-encompassing
error catching, which hides a wide variety of failures -- including outright
code bugs, such as your failure to initialize count. So the first thing I did
was to delete the try-except. You don't really need it here. And even if you
did, you want to declare one or more specific exceptions in the except clause
rather than leaving it wide open.
Work within Python's list indexing as long as possible. It seems that you
want to return human-oriented floor/room numbers (starting at 1) rather
than computer-oriented numbers (starting at 0). That's fine. But defer the
computer-to-human conversion as long as possible. Within the guts of your
algorithmic code, work with Python's indexing scheme. In your case, your
code straddles both, sometimes using 1-based indexing, sometimes 0-based.
That's confusing.
You are resetting count too often. It should be set whenever the room
is full. But you are resetting it whenever count does not equal amount.
As a result, count is almost always being reset to zero.
You are also resetting count too infrequently. It must be reset at the
start of each new floor.
If we make those changes, we get this:
def adjacent_rooms(nested_list, amount):
for i in range(len(nested_list), 0, -1):
count = 0
for j in range(len(nested_list[0])):
if nested_list[i-1][j] == 0:
count += 1
if count == amount:
return (i, j-amount+2)
else:
count = 0
Python lists are directly iterable. As a result, you almost never
need to mess around with list indexes and range() to process list data.
Just iterate directly to access the values. And for those cases where
you need both the value and the index, use enumerate().
Use more declarative variable names. Names like hotel, floor, and
room help the reader understand your code.
Return data, not textual messages. If a function returns a tuple of
integers upon success, what should it do upon non-serious failure? It depends
on the context, but you can either raise an exception or return some variant of
None. In your case, I would probably opt for a parallel tuple: (None, None). This allows the caller to interact with the function in a fairly
natural way and then simply check either value for None. But returning a
textual message is quite unhelpful for callers: the returned data bundle has a
different outer structure (string vs tuple), and it has a different inner data
type (string vs int).
Don't depend on global variables. Pass the hotel data into
the function, as a proper argument.
If we make those changes, we get something like this:
def adjacent_rooms(hotel, wanted):
for fi, floor in enumerate(hotel):
n = 0
for ri, room in enumerate(floor):
if room == 0:
n += 1
if n == wanted:
return (fi + 1, ri - n + 2)
else:
n = 0
return (None, None)
I'm getting the desired output with slightly different indentation:
nested_list_temp = [[0]*7]*5
nested_list = [list(i) for i in nested_list_temp]
nested_list [1][5] = 1
nested_list [2][3] = 1
nested_list [2][4] = 1
nested_list [3][2] = 1
nested_list [4][1] = 1
nested_list [4][5] = 1
def adjacent_rooms(amount):
for i in range(len(nested_list), 0, -1):
count = 0
for j in range(len(nested_list[0])):
if nested_list[i-1][j] == 0:
count += 1
if count == amount:
return (i, j-amount+2)
else:
count = 0
return "not possible to find in one floor"
Another solution:
def adjacent_rooms(nested_list, amount):
to_search = "0" * amount
for floor in range(len(nested_list) - 1, -1, -1):
try:
idx = "".join(map(str, nested_list[floor])).index(to_search)
return "floor no: {}, start from room no: {}".format(
floor + 1, idx + 1
)
except ValueError:
continue
return "not possible to find in one floor"
nested_list = [[0 for _ in range(7)] for _ in range(5)]
nested_list[1][5] = 1
nested_list[2][3] = 1
nested_list[2][4] = 1
nested_list[3][2] = 1
nested_list[4][1] = 1
nested_list[4][5] = 1
for f in range(1, 10):
print("f={}, result: {}".format(f, adjacent_rooms(nested_list, f)))
Prints:
f=1, result: floor no: 5, start from room no: 1
f=2, result: floor no: 5, start from room no: 3
f=3, result: floor no: 5, start from room no: 3
f=4, result: floor no: 4, start from room no: 4
f=5, result: floor no: 2, start from room no: 1
f=6, result: floor no: 1, start from room no: 1
f=7, result: floor no: 1, start from room no: 1
f=8, result: not possible to find in one floor
f=9, result: not possible to find in one floor

Valid seat assumption

I'm having issue with this function question:
x = [[0,0,0,0,0],[0,0,0,0,1],[0,1,0,0,0]]
Function: Book(seat) #assuming the seat is A5
The function assumes the seat is valid in the format A, B and C. the function needs to transform the letter part of seat to an integer A = 0, B = 1 and C = 2. The string digit also needs to be changed to "1" → 0, "2" → 1, "3" → 2, "4" → 3 and "5" → 4. These can be used to check if the chair in the x list-of-lists is already booked 1 or not 0. If it is not booked, then it should be changed to booked and the function should return True else it should return False.
My solution is
a = {"A":[0,0,0,0,0], "B":[0,0,0,0,1], "C":[0,1,0,0,],}
rowIndex = ["A","B","C"]
columnIndex = [1,2,3,4,5]
def book(seat):
row = seat[0]
column = seat[1]
while row in rowIndex and column in columnIndex:
if x[row][column-1] == 0:
return True
else: return False
It output False (seat already booked) in respective of the seat I book. I think there is an issue with my code but can't seems to figure it out.
There are a number of problems with your code for the function:
There is no x variable defined — you called it a in the
a = {"A":[0,0,0,0,0], "B":[0,0,0,0,1], "C":[0,1,0,0,],}
After the
row = seat[0]
column = seat[1]
you then test the values in the following:
while row in rowIndex and column in columnIndex:
which will prevent any of the rest of the code from executing unless it's True.
What you need inside of the while to iterate through all the possibilities would require two for loops, one nested inside the other. However…
You don't need to loop at all as illustrated below.
BOOKED = 1
x = [[0,0,0,0,0], [0,0,0,0,1], [0,1,0,0,0]]
letter_to_index = {"A": 0, "B": 1, "C": 2}
digit_to_index = {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4}
def book(seat):
# Convert each seat character to integer.
row = letter_to_index[seat[0]]
col = digit_to_index[seat[1]]
if x[row][col] == BOOKED:
return False
else:
# Book the seat and return True
x[row][col] = BOOKED
return True
if __name__ == '__main__':
print(book('A5')) # -> True
# Try doing it again.
print(book('A5')) # -> False
Here is a simpler implementation of your code. You don't need to use loops. You have a dictionary. You can lookup the dictionary in a much simpler way.
a = {"A":[0,0,0,0,0], "B":[0,0,0,0,1], "C":[0,1,0,0,],}
def book(seat):
r,c = seat #this allows A to be r and 5 to be C
#check if value of r in keys of a
#also check if seat # is within length of seats for key
if r in a and int(c) <= len(a[r]):
#if valid request, then check if seat already booked
#if not, set seat to booked by setting value to 1
#return True
#if already booked, return False
if a[r][int(c)-1] == 0:
a[r][int(c)-1] = 1
return True
else:
return False
# if not a value request, send appropriate message
else:
return 'invalid request'
print ('A5', book('A5'))
print ('C2', book('C2'))
print ('A7', book('A7'))
print (a)
Output of this will be:
A5 True
C2 False
A7 invalid request
{'A': [0, 0, 0, 0, 1], 'B': [0, 0, 0, 0, 1], 'C': [0, 1, 0, 0]}

Finding values in an unsorted list

so I have this assignment that is telling me to code a quiz about food. I pretty much ask some random questions about food and I have to display 2 of the top recommended foods from what they have answered. I made a list of 8 foods and a score for each one of the foods.
food=["pizza", "hotdogs", "chicken", "apples", "fish", "fries", "burgers", "donuts"]
score=[0,0,0,0,0,0,0,0,0]
print("Please answer each of the questions with yes or no.")
question=input("Do you eat meat?")
if question=="yes":
score[0]=score[0] + 1
score[1]=score[1] + 1
score[2]=score[2] + 1
score[4]=score[4] + 1
score[6]=score[6] + 1
question=input("Do you like fruits?")
if question=="yes":
score[3]=score[3] + 1
question=input("Do you like fried foods?")
if question=="yes":
score[2]=score[2] + 1
score[5]=score[5] + 1
score[4]=score[4] + 1
question=input("Do you like cheese?")
if question=="yes":
score[0]=score[0] + 1
score[1]=score[1] + 1
score[6]=score[6] + 1
question=input("Do you like food with holes in it?")
if question=="yes":
score[7]=score[7] + 1
question=input("Do you like to eat healthy?")
if question=="yes":
score[3]=score[3] + 1
question=input("Do you like bread?")
if question=="yes":
score[1]=score[1] + 1
score[6]=score[6] + 1
question=input("Do you like protein rich foods?")
if question=="yes":
score[2]=score[2] + 1
score[4]=score[4] + 1
question=input("Do you like dessert?")
if question=="yes":
score[3]=score[3] + 1
score[7]=score[7] + 1
question=input("Are you a vegan?")
if question=="yes":
score[3]=score[3] + 1
score[5]=score[5] + 1
score[7]=score[7] + 1
print(food)
print(score)
biggestsofar=0
for i in range(1, len(score)):
if (score[biggestsofar] < score[i]):
biggestsofar = i
print("The biggest value is", biggestsofar)
print("Your recommended food is", food[biggestsofar])
This is what I have so far. The thing I am struggling with is displaying the 2 recommended foods. I found out how to display one of them (which is the code above^) but don't understand how to do the second. I have to somehow find the second biggest number in the list that gets created when they answer the questions. If someone can help me I would appreciate it.(And yes I had to use a loop to find the first one)
Using Dictionary approach
While there are some interesting ways to solve this, i took both the food and questions, converted them into dictionary to help you get the answer.
Step 1: convert the food into a dictionary as keys, and value as scores.
Step 2: convert all the questions into a dictionary as keys and values as a list of items that needs to be scored. Use food list as the index to look up the key and increment. You can also use the value as list of food items.
Step 3: Iterate through the questions and ask the questions
Step 4: If answer is yes, use the food_score dictionary to increment the food by 1
Step 5: Sort the food_score dictionary in reverse order to get the top food items. The first 2 will be the top 2 food items.
food=["pizza", "hotdogs", "chicken", "apples", "fish", "fries", "burgers", "donuts"]
food_score = {f:0 for f in food}
questions = {'Do you eat meat ? ':[0,1,2,4,6],
'Do you like fruits ? ':[3],
'Do you like fried foods ? ':[2,4,5],
'Do you like cheese ? ':[0,1,6],
'Do you like food with holes in it ? ':[7],
'Do you like to eat healthy ? ':[3],
'Do you like bread ? ':[1,6],
'Do you like protein rich foods ? ':[2,4],
'Do you like dessert ? ':[3,7],
'Are you a vegan ? ':[3,5,7]}
print("Please answer each of the questions with yes or no.")
#iterate through all the questions. k is question,
#and v is the elements that needs incremented
for k,v in questions.items():
q = input(k)
if q.lower() == 'yes':
#if answer is yes, then increment each food item by 1
for i in v: food_score[food[i]] +=1
#sort the dictionary by value, in reversed order so first value is highest score
ranked_food = sorted(food_score, key=food_score.get, reverse=True)
print ('The biggest value is : ',food_score[ranked_food[0]])
print ('Your recommended food is : ', ranked_food[0])
print ('The second biggest value is : ', food_score[ranked_food[1]])
print ('Your second recommended food is : ', ranked_food[1])
The first two elements in ranked_food should give you the top 2 food per recommendation.
This solution is flexible and allows you to expand the list of food items and also to expand the question sets. The rest of the code can remain the same and will find the top two food recommendations.
With your existing approach
If you are not allowed to use the new approach, you can do the following:
Assume you are allowed to use zip:
score_food = [(s,f) for s,f in zip(score,food)]
If zip is not allowed, then do this:
score_food = []
for i in range(len(food)):
score_food.append((score[i],food[i]))
Now sort the list in descending order using this:
score_food.sort(reverse=True)
This will give you the scores in descending order. Since you stored them as a tuple, your score and food are paired together and you can identify each of them using the index.
score_food[0] will be the highest ranked. score_food[0][0] will be the score and score_food[0][1] will be the food.
Similarly, score_food[1] will be the second highest ranked. score_food[1][0] will be the score and score_food[1][1] will be the food.
If sort function is not allowed, use any sort logic (bubble sort is simplest to implement), and sort them in descending order. Remember score_food[i][0] will be the score where i ranges from 0 thru 7 (since there are 8 food items).
Another option to implement this is:
score_index = []
for i, s in enumerate(score):
score_index.append((s,i))
Now this is stored as a tuple with score and index pair. Again, this can be sorted and then referenced.
code to sort in descending order
for i in range (len(score_food)-1):
for j in range(i+1,len(score_food)):
if score_food[i][0] < score_food[j][0]:
score_food[i],score_food[j] = score_food[j],score_food[i]
Now you can reference score_food[0] It has highest_score and best_food.
score_food[1] will give you next highest_score and next best_food
I read your question wrong. Sorry :/
Ok, so you want the two largest values, right? My old code still works, but with some modifications. You need to find the index of that value.
lis = [0, 1, 3, 2, 1, 4, 3, 1, 9]
sorted_lis = sorted(lis)
print(lis.index(sorted_lis[-1]), lis.index(sorted_lis[-2]))
Carrying over to your example:
score = [0, 1, 3, 2, 1, 4, 3, 1, 9]
sorted_score = sorted(score)
print(food[score.index(sorted_score[-1])], food[score.index(sorted_score[-2])])
Side note
I'm not sure if you know classes yet, but here's an alternate solution that is cleaner:
class Food(): # create a food class
def __init__(self, type_):
self.type = type_
self.value = 0
def increment(self):
self.value += 1
def __lt__(self, other):
return self.value < other.value
def __le__(self, other):
return self.value <= other.value
def __gt__(self, other):
return self.value > other.value
def __ge__(self, other):
return self.value >= other.value
def __eq__(self, other):
return self.type == other.type
foods = [Food("pizza"), Food("burger"), Food("hot dog")] # make some foods
food_STRING = []
for i in foods:
food_STRING.append(i.type)
for i in range(10):
food = input("Food:")
foods[food_STRING.index(food)].increment()
sorted_food = sorted(foods)
print(sorted_food[-1].type, sorted_food[-2].type)
While other people have given good answers, I recommend you use a dictionary. A dictionary is when you correspond one value (usually a string) to another value (such as a boolean, number, or another string).
I think you should implement this in your code:
# Creating a dictionary (food: score)
my_dictionary = {
'pizza': 0,
'hotdogs': 0,
'chicken': 0,
'apples': 0,
'fish': 0,
'fries': 0,
'burgers': 0,
'donuts': 0,
}
# Creating a function to change the food and score.
# Execute this function to change your score
def change_score(food, score):
global my_dictionary
my_dictionary[food] = score
I'll let you use this to try and finish your program yourself, but this should hopefully be helpful.
This site should help you understand dictionaries:
You can think of the answer as having two buckets for which to you can assign a larger value that the current then check if one is larger than the other and swap them if so. I am assuming your assignment didn't allow for the sort/sorted functions:
largest, second_largest = (0, 0)
for item in range(len(score))):
if score[item] > score[largest]:
second_largest = largest
largest = item
elif score[largest] > score[item] > score[second_largest]:
second_largest = item
print("The biggest value is", score[largest])
print("Your recommended food is", food[largest])
print("The second biggest value is", score[second_largest])
print("Your second recommended food is", food[second_largest])

List manipulation for a Conditional Round-Robin Rugby Draw

One of the Rugby Coaches at my school have asked me to code a conditional rugby match draw for the upcoming games with the task laid out something like this: Given a list of teams from 1 - 12 split into 3 groups ([Group1 = 1, 2, 3, 4], [Group2 = 5, 6, 7, 8,], [Group3 = 9, 10, 11, 12])
generate and print an 11 round-robin matchup with the conditions that:
Teams in Group1 does NOT verse teams in Group3
Teams in Group1 verses every other team in Group 1 twice (Eg. 1v2, 2v1, 1v3, 3v1, 1v4, 4v1, 1v5, 5v1.....)
This same rule applies to teams in Group3 as they verse other teams in Group3
Teams in Group2 verse every other team once.
Teams in Group1 and Group3 need one Bye Game.
I have attempted multiple times but inevitably become stuck, below are my 2 attempts:
Attempt 1:
import operator
import functools
import random
###First Generation (Flawed unclean round robin)
def fixtures(teams):
if len(teams) % 2:
teams.append('Day off') # if team number is odd - use 'day off' as fake team
rotation = list(teams) # copy the list
random.shuffle(rotation)
fixtures = []
for i in range(0, len(teams)-1):
fixtures.append(rotation)
rotation = [rotation[0]] + [rotation[-1]] + rotation[1:-1]
return fixtures
def main():
# demo code
teams = ["Team1","Team2","Team3","Team4","Team5","Team6","Team7","Team8","Team9","Team10","Team11","Team12"]
groupA = ["Team1","Team2","Team3","Team4"]
groupB = ["Team5","Team6","Team7","Team8"]
groupC = ["Team9","Team10","Team11","Team12"]
# for one match each - use this block only
matches = fixtures(teams)
print("flawed matches:")
RoundCounter = 0
homeTeams = []
awayTeams = []
for f in matches:
#print(f)
homeTeams = f[::2]
awayTeams = f[1::2]
print("Home Teams:{}".format(homeTeams))
print("Away Teams:{}".format(awayTeams))
HomeTeamGroupA = set(homeTeams).intersection(groupA)
HomeTeamGroupC = set(homeTeams).intersection(groupC)
AwayTeamGroupA = set(awayTeams).intersection(groupA)
AwayTeamGroupC = set(awayTeams).intersection(groupC)
VSCounter = 0
for p, o in zip(homeTeams, awayTeams):
if p in HomeTeamGroupA:
if o in AwayTeamGroupC:
AvsCPosition = awayTeams.index(o)
VSCounter += 1
RoundCleanUp(homeTeams, awayTeams, AvsCPosition, VSCounter) #if this is returned begin cleaning the round
else: print("GroupA is versing either Group B or GroupA") #if this is returned it is a team 1-4 but is vs either group b or group a
elif p in HomeTeamGroupC:
if o in AwayTeamGroupA:
AvsCPosition = awayTeams.index(o)
VSCounter += 1
RoundCleanUp(homeTeams, awayTeams, AvsCPosition, VSCounter) #if this is returned begin cleaning the round
else:
print("GroupC is versing either Group B or GroupC") #if this is returned it is a team 9-12 but is vs either group b or group c
else:
pass
def RoundCleanUp(HTeam, ATeam, AvsCPos, VSCounter):
##gets Value of List at position
HTeamVal = HTeam[AvsCPos]
ATeamVal = ATeam[AvsCPos]
main()
Attempt 2:
import operator
import functools
import random
def make_round(rotation, num_teams, fixtures):
for i in range(num_teams - 1):
rotation = list(range(1, num_teams + 1))
# clip to 0 .. num_teams - 2 # if i == 0, no rotation is needed (and using -0 as list index will cause problems)
i %= (num_teams - 1)
if i:
rotation = rotation[:1] + rotation[-i:] + rotation[1:-i]
half = num_teams // 2
fixtures.append(list(rotation[:half]))
fixtures.append(list(rotation[half:][::-1]))
return fixtures
def make_schedule(teams):
"""Produces RoundRobin"""
# number of teams must be even
TeamLength = len(teams)
if TeamLength % 2:
TeamLength += 1 # add a dummy team for padding
# build first round-robin
rotation = list(teams)
Fixture = []
schedule = make_round(rotation, TeamLength, Fixture)
return schedule
def homeAwayRotation(matches):
for homeTeams, awayTeams in zip(matches[0::2], matches[1::2]):
print("Home Rotation: {}".format(homeTeams))
print("Away Rotation: {}".format(awayTeams))
validation(homeTeams, awayTeams)
def validation(homeTeams, awayTeams):
groupA = [1, 2, 3, 4]
groupC = [9, 10, 11, 12]
for x, y in zip(homeTeams, awayTeams):
if x in groupA:
if y in groupC:
AvsCPosition = awayTeams.index(y)
cleanDirtyData(homeTeams, awayTeams, AvsCPosition)
else:
# if this is returned it is a team 1-4 but is vs either group b or group a
print("Group A vsing either itself or GroupB\n")
elif x in groupC:
if y in groupA:
AvsCPosition = awayTeams.index(y)
cleanDirtyData(homeTeams, awayTeams, AvsCPosition)
else:
# if this is returned it is a team 9-12 but is vs either group b or group c
print("Group C vsing either itself or GroupB\n")
else:
# if this is returned it is a team in group B
print("This is team B\n")
def cleanDirtyData(homeTeams, awayTeams, AvsCPosition):
HTeamVal = homeTeams[AvsCPosition]
ATeamVal = awayTeams[AvsCPosition]
Dirtlist = []
Dirtlist.append(HTeamVal)
Dirtlist.append(ATeamVal)
def main():
# demo code
teams = ["Team1", "Team2", "Team3", "Team4", "Team5", "Team6",
"Team7", "Team8", "Team9", "Team10", "Team11", "Team12"]
# for one match each - use this block only
matches = make_schedule(teams)
print("flawed matches:")
homeAwayRotation(matches)
main()
My expected results would be printing each round showing which team is versing which and each team having a history a bit like this:
a team in Group1 has a verse history of: (in any random order)
1v2, 2v1, 1v3, 3v1, 1v4, 4v1, 1v5, 1v6, 1v7, 1v8, bye
a team in Group2 has a verse history of: (in any random order)
5v1, 5v2, 5v3, 5v4, 5v6, 5v7, 5v8, 5v9 5v10, 5v11, 5v12
a team in Group3 has a verse history of: (in any random order)
9v10, 10v9, 9v11, 11v9, 9v12, 12v9, 9v5, 9v6, 9v7, 9v8, bye
Any pointers or improvements I could possibly do would be greatly appreciated as I have been stuck on the final hurdle for the last 2 weeks
If I have understood the problem correct, then all you need is some combining of teams with every member in different groups.
I put some code together that should solve your problem:
def vs(team, group):
matchups = map(lambda opponent: (team,opponent), group)
matchups = filter(lambda tup: tup[0] != tup[1], matchups)
return list(matchups)
def matches(teams):
group_size = len(teams) // 3
# Make the groups, basically just splitting the team list in three parts
groups = [teams[:group_size], teams[group_size:2*group_size], teams[2*group_size:]]
matchups = []
for index, team in enumerate(teams):
group_index = index // group_size
current_matchup = []
# Check if we're working with group 1 or 3
if group_index == 0 or group_index == 2:
# Flip the order of a tuple
def flip(x):
return (x[1], x[0])
own_group = vs(team, groups[group_index])
# Add matches against everyone in the group
current_matchup.extend(own_group)
# Add matches agains everyone in the group again, but now the current team is 'away'
current_matchup.extend(list(map(flip, own_group)))
# Add matches against everyone in group 2
current_matchup.extend(vs(team, groups[1]))
# Lastly, add the bye
current_matchup.append((team, "bye"))
else:
# Just all matches against all other teams, once.
current_matchup.extend(vs(team, teams))
matchups.append(current_matchup)
return matchups
# This can be anything. Numbers, 'Team 1' or even 'The wondrous flying squirrels of death'
teams = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
# Make matches
matchups = matches(teams)
# Just pretty print
for i in range(len(matchups)):
matches = '\n\t'.join(map(lambda m: f'{str(m[0]).rjust(10)} vs {str(m[1]).ljust(10)}', matchups[i]))
print(f"Team '{teams[i]}' matches:\n\t{matches}")

Python dictionary merge up two dictionaries and building cumulative

I have two arrays date_IN and date_OUT that contain the dates when animals come in and leave the farm. Now I want to plot the total population over time.
date_IN, date_OUT
26.09.1999,19.12.2006
26.09.1999,19.01.2005
26.09.1999,15.02.2007
26.09.1999,29.03.2006
...
I tried to first count the entries for each day, subtract the number of animals that leave the farm from the number of animals that come in and then sum up the sorted values.
But unfortunately the subtraction doesn't work.
date_EIN, date_AUS=np.genfromtxt("Gesamtbestand.txt",delimiter=',',unpack = True, converters={ 0: mdates.strpdate2num('%d.%m.%Y'), 1: mdates.strpdate2num('%d.%m.%Y') or 0})
c = Counter(date_EIN)
d = Counter(date_AUS)
tn_each_day = c - d
sorted_keys = sorted(tn_each_day,key=tn_each_day.get)
z = cumsum(sorted(d.values())) # or z = cumsum([d[k] for k in sorted_keys])
tn = dict(zip(sorted_keys,z))
Does anyone have an idea how to fix this?
For brevity, let's use numbers instead of dates:
>>> from collections import Counter
>>> import itertools as it
>>> import operator as op
>>> ein = Counter([1,2,2,3,3])
>>> aus = Counter([1,2,3,4])
>>> delta = {k:ein.get(k,0)-aus.get(k,0) for k in set(it.chain(ein,aus))}
>>> delta
{1: 0, 2: 1, 3: 1, 4: -1}
>>> sorted_dates = sorted(delta)
>>> population = dict(zip(sorted_dates, it.accumulate((delta[k] for k in sorted_dates), add)))
>>> population
{1: 0, 2: 1, 3: 2, 4: 1}
i.e. for each date, population holds the number of animals present in the farm.
e.g.
on date 1 one animal went in and one went out -> 0 farm population
on date 2 two animals went in and one went out -> 1 farm population
on date 3 two animals went in and one went out -> 2 farm population
on date 4 zero animals went in and one went out -> 1 farm population
Subtracting a Counter from another Counter just removes the keys that exist in both Counters from the first Counter. This is not what you are trying to do. Here's a working example:
from collections import Counter
def compareDates(d1, d2):
d1, d2 = d1.split('.'), d2.split('.')
for i in range(2,-1,-1):
if d1[i] > d2[i]:
return 1
if d1[i] < d2[i]:
return -1
return 0
IN = ['26.09.1999', '26.09.1999', '26.09.1999', '26.09.1999', '26.8.2008']
OUT = ['19.12.2006', '19.01.2005', '15.02.2007', '29.03.2006', '27.8.2008']
c_IN = Counter(IN)
c_OUT = Counter(OUT)
tn_each_day = {}
for date, count in c_IN.items():
if date not in tn_each_day :
tn_each_day[date] = 0
tn_each_day[date] += count
for date, count in c_OUT.items():
if date not in tn_each_day :
tn_each_day [date] = 0
tn_each_day[date] -= count
cumulative = {}
population = 0
for date in sorted(tn_each_day, cmp=compareDates):
population += tn_each_day[date]
cumulative[date] = population
print '{}: {}'.format(date, population)
This produces an output of:
26.09.1999: 4
19.01.2005: 3
29.03.2006: 2
19.12.2006: 1
15.02.2007: 0
26.8.2008: 1
27.8.2008: 0

Categories