Reduce iterations in a sorting algorithm - python

Let's say I have a list that I want to sort based on subjective criteria, such as the user's personal preferences. In this case, just using the input() function.
The goal is to minimize the number of iterations and maximize the certainty of the algorithm.
In the example below, I implement a simple algorithm that selects two items at random from the list and asks the user which one they prefer. It then transfers a percentage of the assigned coefficient, from the not chosen item to the item chosen. And it takes away a chosen item percentage from the not chosen item.
How can I minimize the number of iterations without disturbing the certainty of the algorithm?
# Assign a coefficient to each element initialized to 1.0
def ListToDict(list_of_items):
food_dict = {}
for item in list_of_items:
food_dict[item] = 1.0
return food_dict
# Ask the user to choose between two items
def AskUser(item_name_one, item_name_two):
print("\n [" + item_name_one + "] or [" + item_name_two + "] ?")
user_choice = input("--> ")
if user_choice == "1" or user_choice == "2":
return int(user_choice)
else:
print("\nONLY 1 OR 2 PLEASE!")
return AskUser(item_name_one, item_name_two)
# The PerformSort() function update the coefficient of each item.
# For each step, the user will be asked to choose between two items.
# If the user chooses the first item,
# the coefficient of the first item will be increased by 0.1 times the coefficient of the second item,
# and the coefficient of the second item will be decreased by 0.1 times the coefficient of the first item.
# The opposite happens if the user chooses the second item.
# When the number_of_iterations parameter is high,
# the certainty of the result will be higher but the user will have to answer more questions.
def PerformSort(my_dict, number_of_iterations):
from random import randint
length_of_dict = len(my_dict)
for i in range(number_of_iterations):
print("\n---- ITERATION " + str(i + 1) + " ----")
remaining_items = list(my_dict.keys())
while len(remaining_items) > 1:
item_one = remaining_items[randint(0, len(remaining_items) - 1)]
item_two = remaining_items[randint(0, len(remaining_items) - 1)]
while item_one == item_two:
item_two = remaining_items[randint(0, len(remaining_items) - 1)]
user_choice = AskUser(item_one, item_two)
if user_choice == 1:
my_dict[item_one] += 0.1 * my_dict[item_two]
my_dict[item_two] -= 0.1 * my_dict[item_one]
elif user_choice == 2:
my_dict[item_one] -= 0.1 * my_dict[item_two]
my_dict[item_two] += 0.1 * my_dict[item_one]
remaining_items.remove(item_one)
remaining_items.remove(item_two)
return my_dict
# Get the list of items sorted by their coefficient
def OrderByCoeficient(food_dict):
list_of_keys = list(food_dict.keys())
list_of_keys.sort(key=lambda x: food_dict[x], reverse=True)
return list_of_keys
if __name__ == "__main__":
items_to_sort = [ "pizza", "cheeseburger", "beef", "soup", "ice cream" ]
my_dict = ListToDict(items_to_sort)
my_dict = PerformSort(my_dict, 3)
print("\n Here's your list from highest to lowest:")
print(OrderByCoeficient(my_dict))

I'd suggest just doing a regular sort by turning your AskUser into a comparator function and using functools.cmp_to_key() to turn it into a sorting key function. That way you can take advantage of sort's built-in efficiency to minimize the number of comparisons, without having to invent and tune your own sorting algorithm.
import functools
def ask_user_cmp(item1, item2):
while True:
print(f"[{item1}](1) or [{item2}](2) ?")
cmp = input("--> ")
if cmp == "1":
return 1
if cmp == "2":
return -1
print("1 or 2, please!")
ask_user_key = functools.cmp_to_key(ask_user_cmp)
items_to_sort = ["pizza", "cheeseburger", "beef", "soup", "ice cream"]
items_to_sort.sort(key=ask_user_key, reverse=True)
print("Here's your list from highest to lowest:")
print(items_to_sort)
[soup](1) or [ice cream](2) ?
--> 2
[beef](1) or [soup](2) ?
--> 2
[cheeseburger](1) or [beef](2) ?
--> 1
[cheeseburger](1) or [soup](2) ?
--> 1
[cheeseburger](1) or [ice cream](2) ?
--> 2
[pizza](1) or [cheeseburger](2) ?
--> 1
[pizza](1) or [ice cream](2) ?
--> 2
Here's your list from highest to lowest:
['ice cream', 'pizza', 'cheeseburger', 'soup', 'beef']
Comparing this with the results of running your code and giving the same answers:
---- ITERATION 1 ----
[cheeseburger] or [soup] ?
--> 1
[pizza] or [beef] ?
--> 1
---- ITERATION 2 ----
[soup] or [beef] ?
--> 1
[ice cream] or [pizza] ?
--> 1
---- ITERATION 3 ----
[beef] or [soup] ?
--> 2
[ice cream] or [pizza] ?
--> 1
Here's your list from highest to lowest:
['ice cream', 'cheeseburger', 'soup', 'pizza', 'beef']
Note that your code asked me two redundant questions (ice cream vs pizza and beef vs soup were both asked twice), and it never figured out that I like pizza better than either cheeseburgers or soup.

Related

Transform the 2d list of poker stacks into list of actions

All poker stacks are scraped every few seconds during one poker hand on the preflop. Here's the list of list of stacks in the big blinds(BB). Player 4 makes mandatory bet 0.5 BB, Player 5 makes 1 BB bet at the start, then players act consecutively from 0 to 5. The first sublist is player 0, the last is player 5.
Return list of actions.
Example 1: [[102,102,102,102]
[101,101,99,99]
[103.5,103.5,103.5]
[100.5,100.5,100.5,93,79.5]
[105.5,105.0,105.0,105.0]
[94,93,93,93,93,73]]
Desired output 1: Fold - Raise 2 - Fold - Raise 7.5 - Fold - Raise 21 - Fold - Call.
Explanation:
Player 0 folded because there's no change in his stack.
Player 1 raised 2 because the stack decreased 101 - 99 = 2 big blinds (BB).
Player 2 folded because there's no change in his stack.
Player 3 raised because the stack decreased 100.5 - 93 = 7.5 big blinds and the decrease is larger than previous bet (2 big blinds).
Player 4 folded because there's no change in his stack after posting small blind (0.5 big blinds or BB).
Player 5 raised 21 because the his overall stack decreased 93 - 73 = 20 big blinds, he also posted 1 big blind so his overall raise size is 20 + 1 = 21).
Player 1 folded because the stack doesn't decrease after his bet.
Player 3 called 21 because his stack decreased 93 - 79.5 = 13.5 BB and his overall bet in the round is 13.5 + 7.5 = 21 BB which equals maximum raise size in current round.
I correctly wrote transform_stacks function that transfroms list of stacks sizes into list of differences, however get_actions function is completely incorrect.
from more_itertools import pairwise
from itertools import zip_longest
 
stacks = [[102,102,102,102], [101,101,99,99], [103.5,103.5,103.5], [100.5,100.5,100.5,93,79.5], [105.5,105.0,105.0,105.0], [94,93,93,93,93,73]]
 
def transform_stacks(stacks): # finds the difference in stack sizes, the functions is normal
u = [[float(x) - float(y) for (x, y) in pairwise(stacks[z]) if x != '' and y != '' and abs(float(y) - float(x)) > 0.499] for z in range(len(stacks))]
#print(u)
#will return [[], [2.0], [], [7.5, 13.5], [0.5], [1.0, 20.0]]
return u
 
transposed = transform_stacks(stacks)
 
def get_actions(stacks):
actions = []
for index in range(len(stacks)):
curr_max = 0
for k in range(len(stacks[index])):
if stacks[index][k] and (stacks[index][k] - 0.01 > curr_max):
actions.append("Raise " + str(stacks[index][k]))
curr_max = stacks[index][k]
elif stacks[index][k]:
actions.append("Call " + str(stacks[index][k]))
 
return actions
print(get_actions(transposed)) # should print ['Fold','Raise 2','Fold','Raise 7.5,'Fold','Raise 21','Fold','Call']
I can't test it right now but try if this works. It might look a bit longer than what you had but I think it's a very intuitive way of going at this problem:
from itertools import accumulate
def get_actions(stacks):
# this part should probably go in the transform_stacks function
# what it does is give you the cumulative total rather than the individual raises
# this makes sense because you want the output to be "raise 21"
# for the BB in the example, rather than "raise 20"
stacks = [list(accumulate(x)) for x in stacks]
SB = None
for i, stack in enumerate(stacks):
try:
if stack[0] == 0.5:
SB = i
break
except IndexError:
continue
# just to make sure
if SB is None:
raise ValueError("Small Blind not found")
num_players = len(stacks)
stacks[SB].pop(0)
bet = stacks[(SB+1)%num_players].pop(0)
action_on_player = (SB+2)%num_players
action_strings, out_of_hand = [], []
while any(stacks):
if action_on_player in out_of_hand:
action_on_player = (action_on_player+1)%num_players
continue
if not stacks[action_on_player]:
action_strings.append("Fold")
out_of_hand.append(action_on_player)
action_on_player = (action_on_player+1)%num_players
continue
action = stacks[action_on_player].pop(0)
if action == bet:
action_strings.append("Call")
else:
action_strings.append("Raise " + str(action))
bet = action
action_on_player = (action_on_player+1)%num_players
return action_strings

Is there a reason as to why my program is not outputting anything?

This post is about a problem that I have encountered on a challenge that was assigned to me. The challenge is: you are in a pizza shop, and you are making software to calculate the price of orders. There are 4 customer inputs: pizza, drinks, wings, and coupons. the customer can order any arbitrary number of pizzas - including zero - and this goes for all of the other inputs. the wings, drinks, and coupons are all keyworded inputs, whereas the pizzas are not. All inputs are in lists, except the coupon is stored in a list. Pizzas can have any number of toppings, and people are charged extra for each topping. Here is a sample input:
cost_calculator([], ['pepperoni', 'mushroom'], drinks = ['tub', 'small'], wings = [10, 20], coupon = 0.1)
In the above example, the "[], [pepperoni, mushroom]" details two pizzas, the "drinks = ['tub', 'small']" details two drinks, the "wings = [10,20]" details two orders of wings (10-piece, 20-piece), and the coupon takes 10% off the order.
Additionally, there is a tax of 6.25% which is added at the end of the program.
The problem is that the code that I have written does not output anything. I have looked it over countless times and I am not sure why it doesn't work. If one is interested in the challenge I am attempting - here is the link. Before anyone tells me that there is no print function - I know, there is a grader that I input this into, but for testing, I have been using print functions, and they still are not outputting anything. Forward apology for my terrible variables/
def cost_calculator(*pizza, **others):
# write your code here
call = ((toppers(pizza) + drinkers(others) + wingers(others)))
interest = (call * coupons(others)) + (call * 0.0625)
return round(interest, 2)
def toppers(toppers):
if (len(toppers) == 0):
return 0
topCost = 13.00
j = 0
toppings = {"pepperoni" : 1.00, "mushroom": 0.5, "olive": 0.5, "anchovy": 2.00, "ham" : 1.5}
while (j < len(toppers)):
for i in toppers:
b = 0
for thing in i:
gg = thing[b]
if gg in toppings:
topCost += toppings[gg]
j+=1
return topCost
def drinkers (drinkers):
drinks = {"small" : 2.00, "medium" : 3.00, "large":3.5, "tub":3.75}
pricers = 0.00
r = 0
while (r < len(drinkers)):
for key, i in wingers:
b = 0
if key == "drinks":
for thing in i:
gg = thing[b]
if gg in drinks:
pricers += drinks[gg]
r+=1
return pricers
def wingers (wingers):
if (len(wingers) == 0):
return 0
wings = {10:5.00 , 20:9.00 , 40:17.50, 100:48.00}
wingices = 0.00
kk = 0
while (kk < len(wingers)):
for key, i in wingers:
b = 0
if key == "wings":
for thing in i:
gg = thing[b]
if gg in wings:
wingices += wings[gg]
kk+=1
return wingices
def coupons(cups):
cupz = 1.00
for key,i in cups.items():
if key == "coupon":
cupz = 0.00
cupz += i
return 1 - cupz
return cupz
Your code does run into an endless loop here:
def toppers(toppers):
if (len(toppers) == 0):
return 0
topCost = 13.00
j = 0
toppings = {"pepperoni": 1.00, "mushroom": 0.5, "olive": 0.5, "anchovy": 2.00, "ham": 1.5}
while (j < len(toppers)):
for i in toppers:
b = 0
for thing in i:
gg = thing[b]
if gg in toppings:
topCost += toppings[gg]
j += 1
return topCost
You call this with a list of two strings (toppers). You start with index j = 0.
Then you iterate over the two items in toppers. Then within each item you iterate over the characters in that item. Then you check if the item string has the bth character (always the 0th character since you don't change b) as key of toppings. Which it never does. So you endlessly check if p (first letter of pepperoni) is a key in toppings and since it never is you never increase j and get stuck endlessly.
You probably want to do something else, probably it would be helpful to break it down into smaller steps and e.g. print() to see if it does the right thing up until that point.
Also I think you use way too many and complicated loop structures. Here is how you could write the method in a simpler way:
def get_cost_for_toppers(toppers):
if len(toppers) == 0:
return 0
# dictionary of costs
available_toppings = {"pepperoni": 1.00, "mushroom": 0.5, "olive": 0.5, "anchovy": 2.00, "ham": 1.5}
# base cost
topCost = 13.00
# iterate over the strings in toppers
for t in toppers:
# add the price found in dictionary for this topper
if t in available_toppings:
topCost += available_toppings[t]
return topCost

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

Changing this Python program to have function def()

The following Python program flips a coin several times, then reports the longest series of heads and tails. I am trying to convert this program into a program that uses functions so it uses basically less code. I am very new to programming and my teacher requested this of us, but I have no idea how to do it. I know I'm supposed to have the function accept 2 parameters: a string or list, and a character to search for. The function should return, as the value of the function, an integer which is the longest sequence of that character in that string. The function shouldn't accept input or output from the user.
import random
print("This program flips a coin several times, \nthen reports the longest
series of heads and tails")
cointoss = int(input("Number of times to flip the coin: "))
varlist = []
i = 0
varstring = ' '
while i < cointoss:
r = random.choice('HT')
varlist.append(r)
varstring = varstring + r
i += 1
print(varstring)
print(varlist)
print("There's this many heads: ",varstring.count("H"))
print("There's this many tails: ",varstring.count("T"))
print("Processing input...")
i = 0
longest_h = 0
longest_t = 0
inarow = 0
prevIn = 0
while i < cointoss:
print(varlist[i])
if varlist[i] == 'H':
prevIn += 1
if prevIn > longest_h:
longest_h = prevIn
print("",longest_h,"")
inarow = 0
if varlist[i] == 'T':
inarow += 1
if inarow > longest_t:
longest_t = inarow
print("",longest_t,"")
prevIn = 0
i += 1
print ("The longest series of heads is: ",longest_h)
print ("The longest series of tails is: ",longest_t)
If this is asking too much, any explanatory help would be really nice instead. All I've got so far is:
def flip (a, b):
flipValue = random.randint
but it's barely anything.
import random
def Main():
numOfFlips=getFlips()
outcome=flipping(numOfFlips)
print(outcome)
def getFlips():
Flips=int(input("Enter number if flips:\n"))
return Flips
def flipping(numOfFlips):
longHeads=[]
longTails=[]
Tails=0
Heads=0
for flips in range(0,numOfFlips):
flipValue=random.randint(1,2)
print(flipValue)
if flipValue==1:
Tails+=1
longHeads.append(Heads) #recording value of Heads before resetting it
Heads=0
else:
Heads+=1
longTails.append(Tails)
Tails=0
longestHeads=max(longHeads) #chooses the greatest length from both lists
longestTails=max(longTails)
return "Longest heads:\t"+str(longestHeads)+"\nLongest tails:\t"+str(longestTails)
Main()
I did not quite understand how your code worked, so I made the code in functions that works just as well, there will probably be ways of improving my code alone but I have moved the code over to functions
First, you need a function that flips a coin x times. This would be one possible implementation, favoring random.choice over random.randint:
def flip(x):
result = []
for _ in range(x):
result.append(random.choice(("h", "t")))
return result
Of course, you could also pass from what exactly we are supposed to take a choice as a parameter.
Next, you need a function that finds the longest sequence of some value in some list:
def longest_series(some_value, some_list):
current, longest = 0, 0
for r in some_list:
if r == some_value:
current += 1
longest = max(current, longest)
else:
current = 0
return longest
And now you can call these in the right order:
# initialize the random number generator, so we get the same result
random.seed(5)
# toss a coin a hundred times
series = flip(100)
# count heads/tails
headflips = longest_series('h', series)
tailflips = longest_series('t', series)
# print the results
print("The longest series of heads is: " + str(headflips))
print("The longest series of tails is: " + str(tailflips))
Output:
>> The longest series of heads is: 8
>> The longest series of heads is: 5
edit: removed the flip implementation with yield, it made the code weird.
Counting the longest run
Let see what you have asked for
I'm supposed to have the function accept 2 parameters: a string or list,
or, generalizing just a bit, a sequence
and a character
again, we'd speak, generically, of an item
to search for. The function should return, as the value of the
function, an integer which is the longest sequence of that character
in that string.
My implementation of the function you are asking for, complete of doc
string, is
def longest_run(i, s):
'Counts the longest run of item "i" in sequence "s".'
c, m = 0, 0
for el in s:
if el==i:
c += 1
elif c:
m = m if m >= c else c
c = 0
return m
We initialize c (current run) and m (maximum run so far) to zero,
then we loop, looking at every element el of the argument sequence s.
The logic is straightforward but for elif c: whose block is executed at the end of a run (because c is greater than zero and logically True) but not when the previous item (not the current one) was not equal to i. The savings are small but are savings...
Flipping coins (and more...)
How can we simulate flipping n coins? We abstract the problem and recognize that flipping n coins corresponds to choosing from a collection of possible outcomes (for a coin, either head or tail) for n times.
As it happens, the random module of the standard library has the exact answer to this problem
In [52]: random.choices?
Signature: choices(population, weights=None, *, cum_weights=None, k=1)
Docstring:
Return a k sized list of population elements chosen with replacement.
If the relative weights or cumulative weights are not specified,
the selections are made with equal probability.
File: ~/lib/miniconda3/lib/python3.6/random.py
Type: method
Our implementation, aimed at hiding details, could be
def roll(n, l):
'''Rolls "n" times a dice/coin whose face values are listed in "l".
E.g., roll(2, range(1,21)) -> [12, 4] simulates rolling 2 icosahedron dices.
'''
from random import choices
return choices(l, k=n)
Putting this together
def longest_run(i, s):
'Counts the longest run of item "i" in sequence "s".'
c, m = 0, 0
for el in s:
if el==i:
c += 1
elif c:
m = m if m >= c else c
c = 0
return m
def roll(n, l):
'''Rolls "n" times a dice/coin whose face values are listed in "l".
E.g., roll(2, range(1,21)) -> [12, 4] simulates rolling 2 icosahedron dices.
'''
from random import choices
return choices(l, k=n)
N = 100 # n. of flipped coins
h_or_t = ['h', 't']
random_seq_of_h_or_t = flip(N, h_or_t)
max_h = longest_run('h', random_seq_of_h_or_t)
max_t = longest_run('t', random_seq_of_h_or_t)

"Josephus-p‌r‌o‌b‌l‌e‌m" using list in python

I wanted to know if it will be possible to solve the Josepheus problem using list in python.
In simple terms Josephus problem is all about finding a position in a circular arrangement which would be safe if executions were handled out using a skip parameter which is known beforehand.
For eg : given a circular arrangement such as [1,2,3,4,5,6,7] and a skip parameter of 3, the people will be executed in the order as 3,6,2,7,5,1 and position 4 would be the safe.
I have been trying to solve this using list for some time now, but the index positions becomes tricky for me to handle.
a=[x for x in range(1,11)]
skip=2
step=2
while (len(a)!=1):
value=a[step-1]
a.remove(value)
n=len(a)
step=step+skip
large=max(a)
if step>=n:
diff=abs(large-value)
step=diff%skip
print a
Updated the question with code snippet, but i don't think my logic is correct.
Quite simply, you can use list.pop(i) to delete each victim (and get his ID) in a loop. Then, we just have to worry about wrapping the indices, which you can do just by taking the skipped index mod the number of remaining prisoners.
So then, the question solution becomes
def josephus(ls, skip):
skip -= 1 # pop automatically skips the dead guy
idx = skip
while len(ls) > 1:
print(ls.pop(idx)) # kill prisoner at idx
idx = (idx + skip) % len(ls)
print('survivor: ', ls[0])
Test output:
>>> josephus([1,2,3,4,5,6,7], 3)
3
6
2
7
5
1
survivor: 4
In [96]: def josephus(ls, skip):
...: from collections import deque
...: d = deque(ls)
...: while len(d)>1:
...: d.rotate(-skip)
...: print(d.pop())
...: print('survivor:' , d.pop())
...:
In [97]: josephus([1,2,3,4,5,6,7], 3)
3
6
2
7
5
1
survivor: 4
If you do not want to calculate the index, you can use the deque data structure.
My solution uses a math trick I found online here: https://www.youtube.com/watch?v=uCsD3ZGzMgE
It uses the binary way of writing the number of people in the circle and the position where the survivor sits. The result is the same and the code is shorter.
And the code is this:
numar_persoane = int(input("How many people are in the circle?\n")) #here we manually insert the number of people in the circle
x='{0:08b}'.format(int(numar_persoane)) #here we convert to binary
m=list(x) #here we transform it into a list
for i in range(0,len(m)): #here we remove the first '1' and append to the same list
m.remove('1')
m.append('1')
break
w=''.join(m) #here we make it a string again
print("The survivor sits in position",int(w, 2)) #int(w, 2) makes our string a decimal number
if you are looking for the final result only, here is a simple solution.
def JosephusProblem(people):
binary = bin(people) # Converting to binary
winner = binary[3:]+binary[2] # as the output looks like '0b101001'. removing 0b and adding the 1 to the end
print('The winner is',int(winner,2)) #converting the binary back to decimal
If you are looking for the math behind this code, go check out this video:
Josephus Problem(youTube)
it looks worse but easier to understand for beginners
def last(n):
a=[x for x in range(1,n+1)]
man_with_sword = 1
print(a)
while len(a)!=1:
if man_with_sword == a[len(a)-2]: #man_with_sword before last in circle
killed = a[len(a)-1]
a.remove(killed)
man_with_sword=a[0]
elif man_with_sword==a[len(a)-1]: #man_with_sword last in circle
killed = a[0]
a.remove(killed)
man_with_sword=a[0]
else:
i=0
while i < (len(a)//2):
i=a.index(man_with_sword)
killed = a[a.index(man_with_sword)+1]
a.remove(killed)
#pass the sword
man_with_sword=a[i+1] # pass the sword to next ( we killed next)
print (a, man_with_sword) #show who survived and sword owner
i+=1
print (a, man_with_sword,'next circle') #show who survived and sword owner
The total number of persons n and a number k, which indicates that k-1 persons are skipped and a kth person is killed in the circle.
def josephus(n, k):
if n == 1:
return 1
else:
return (josephus(n - 1, k) + k-1) % n + 1
n = 14
k = 2
print("The chosen place is ", josephus(n, k))
This is my solution to your question:
# simple queue implementation<ADT>
class Queue:
def __init__(self):
self.q = []
def enqueue(self,data):
self.q.insert(0,data)
def dequeue(self):
self.q.pop()
def sizeQ(self):
return len(self.q)
def printQ(self):
return self.q
lists = ["Josephus","Mark","Gladiator","Coward"]
to_die = 3
Q = Queue()
# inserting element into Q
for i in lists:
Q.enqueue(i)
# for size > 1
while Q.sizeP() > 1:
for j in range(1,3):
# every third element to be eliminated
Q.enqueue(Q.dequeue())
Q.dequeue()
print(Q.printQ())
def Last_Person(n):
person = [x for x in range(1,n+1)]
x = 0
c = 1
while len(person) > 1:
if x == len(person) - 1:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[0])
person.pop(0)
x = 0
c = c+1
elif x == len(person) - 2:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[x + 1])
person.pop(x+1)
x = 0
c = c + 1
else:
print("Round ", c, "- Here's who is left: ", person, "Person ", person[x], "killed person", person[x + 1])
person.pop(x + 1)
x = x + 1
c = c + 1
print("Person", person[x], "is the winner")
Last_Person(50)

Categories