Difference between stock[item] -= 1 and stock[item] = stock[item] - 1? - python

I've trying to write a small program that computes a bill based on certain lists. One of the requirements is to change to stock depending on what is taken out. I wrote my code the following way, and at least conceptually speaking, feel like I have the right idea.
shopping_list = ["banana", "orange", "apple"]
stock = {
"banana": 6,
"apple": 0,
"orange": 32,
"pear": 15
}
prices = {
"banana": 4,
"apple": 2,
"orange": 1.5,
"pear": 3
}
def compute_bill(food):
total = 0
for item in food:
if stock[item] > 0:
total += prices[item]
stock[item] = stock[item] - 1
return total
else:
return "Sorry: Out of Stock"
return total
Unfortunately it doesn't work. I've looked up a potential solution and found one that goes like this.
groceries = ["banana", "orange","apple"]
stock = {"banana": 6,
"apple": 0,
"orange": 32,
"pear": 15
}
prices = {"banana": 4,
"apple": 2,
"orange": 1.5,
"pear": 3
}
def computeBill(food):
total = 0
for item in food:
if stock[item] > 0:
total += prices[item]
stock[item] -= 1
return total
print computeBill(groceries)
The main difference I see lies in these pieces of code:
stock[item] = stock[item] - 1
stock[item] -= 1
What is the main difference between the two and why does the second one work? And what exactly does "-=" do? I could understand if it was a different method of getting the same thing to work, but that they're not equivalent leaves me confounded. Any input would be greatly appreciated and apologies in advance for my ignorance/stupidity.

With numerical variables, the operator -= is exactly the same as assigning one less than the current value. But there's another difference between the two versions: Your solution returns a value as soon as you examine one element in your shopping list. Returning terminates the function, so only do it when you're done calculating.

The problem is likely this:
for item in food:
if stock[item] > 0:
total += prices[item]
stock[item] = stock[item] - 1
return total
Here, you're returning in the middle of the loop, so it will only ever process one item from food. In the second example, the only return statement is at the end of the loop.

What better way to show you the difference but by running a program that demonstrates the difference? Try running the following program and noting what it prints to your screen.
#! /usr/bin/env python3
def main():
stock = dict(apple=Number(100))
item = 'apple'
print('Memory location of stock[item]:', id(stock[item]))
stock[item] -= 1
print('Memory location of stock[item]:', id(stock[item]))
stock[item] = stock[item] - 1
print('Memory location of stock[item]:', id(stock[item]))
class Number:
__slots__ = '__value'
def __init__(self, value):
self.__value = value
def __repr__(self):
return repr(self.__value)
def __sub__(self, other):
type_of_self = type(self)
if isinstance(other, type_of_self):
other = other.__value
return type_of_self(self.__value - other)
def __isub__(self, other):
if isinstance(other, type(self)):
other = other.__value
self.__value -= other
return self
if __name__ == '__main__':
main()
The first operation may alter the object in place. The second operation will create a new object and replace the old one. Please note that is answers your question but not solve your problem.

I am not sure in python, however it could be that the first is decrementing the pointer (ie the actual array) and the second is decrementing the value stored in the pointer.
One way to check is to post the output with fixed values in the where the item variable is.

Related

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

Using the result from a function in a new one (plus more)

I am trying to do the following:
1) calculate the amount of the same numbers in the data list. eg : there are three numbers between and including 10 and 20.
2) represent the value for each number range with the same number of '#'. eg: there are 3 numbers between 10 and 20 = ###.
Ideally ending in having the two values represented next to each other.
Unfortunately I really can't figure out step two and any help would really be appreciated.
My code is below:
def count_range_in_list(li, min, max):
ctr = 0
for x in li:
if min <= x <= max:
ctr += 1
return ctr
def amountOfHashes(count_range_in_list,ctr):
ctr = count_range_in_list()
if ctr == 1:
print ('#')
elif ctr == 2:
print ('##')
elif ctr == 3:
print ('###')
elif ctr == 4:
print ('####')
elif ctr == 5:
print ('#####')
elif ctr == 6:
print ('######')
elif ctr == 7:
print ('#######')
elif ctr == 8:
print ('########')
elif ctr == 9:
print ('#########')
elif ctr == 10:
print ('##########')
data = [90,30,13,67,85,87,50,45,51,72,64,69,59,17,22,23,44,25,16,67,85,87,50,45,51]
print(count_range_in_list(data, 0, 10),amountOfHashes)
print(count_range_in_list(data, 10, 20),amountOfHashes)
print(count_range_in_list(data, 20, 30),amountOfHashes)
print(count_range_in_list(data, 30, 40),amountOfHashes)
print(count_range_in_list(data, 40, 50),amountOfHashes)
print(count_range_in_list(data, 50, 60),amountOfHashes)
print(count_range_in_list(data, 60, 70),amountOfHashes)
print(count_range_in_list(data, 70, 80),amountOfHashes)
print(count_range_in_list(data, 80, 90),amountOfHashes)
print(count_range_in_list(data, 90, 100),amountOfHashes)
I'll start by clearing out some doubts you seem to have.
First, how to use the value of a function inside another one:
You don't need to pass the reference of a method to another here. What I mean is, in amountOfHashes(count_range_in_list,ctr) you can just drop count_range_in_list as a parameter, and just define it like amountOfHashes(ctr). Or better yet, use snake case in the method name instead of camel case, so you end up with amount_of_hashes(ctr). Even if you had to execute count_range_in_list inside amount_of_hashes, Python is smart enough to let you do that without having to pass the function reference, since both methods are inside the same file already.
And why do you only need ctr? Well, count_range_in_list already returns a counter, so that's all we need. One parameter, named ctr. In doing so, to "use the result from a function in a new one", we could:
def amount_of_hashes(ctr):
...
# now, passing the value of count_range_in_list in amount_of_hashes
amount_of_hashes(count_range_in_list(data, 10, 20))
You've figured out step 1) quite well already, so we can go to step 2) right away.
In Python it's good to think of iterative processes such as yours dynamically rather than in hard coded ways. That is, creating methods to check the same condition with a tiny difference between them, such as the ones in amountOfHashes, can be avoided in this fashion:
# Method name changed for preference. Use the name that best fits you
def counter_hashes(ctr):
# A '#' for each item in a range with the length of our counter
if ctr == 0:
return 'N/A'
return ''.join(['#' for each in range(ctr)])
But as noted by Roland Smith, you can take a string and multiply it by a number - that'll do exactly what you think: repeat the string multiple times.
>>> 3*'#'
###
So you don't even need my counter_hashes above, you can just ctr*'#' and that's it. But for consistency, I'll change counter_hashes with this new finding:
def counter_hashes(ctr):
# will still return 'N/A' when ctr = 0
return ctr*'#' or 'N/A'
For organization purposes, since you have a specific need (printing the hashes and the hash count) you may then want to format right what comes into print, you could make a specific method for the printing, that calls both counter_hashes and count_Range_in_list, and gives you a cleaner result afterwards:
def hash_range(data, min, max):
ctr = count_range_in_list(data, min, max)
hashes = counter_hashes(ctr)
print(f'{hashes} | {ctr} items in range')
The use and output of this would then become:
>>> data = [90,30,13,67,85,87,50,45,51,72,64,69,59,17,22,23,44,25,16,67,85,87,50,45,51]
>>> hash_range(data, 0, 10)
N/A | 0 items in range
>>> hash_range(data, 10, 20)
### | 3 items in range
>>> hash_range(data, 20, 30)
#### | 4 items in range
And so on. If you just want to print things right away, without the hash_range method above, it's simpler but more lengthy/repetitive if you want a oneliner:
>>> ctr = count_range_in_list(data, 10, 20)
>>> print(counter_hashes(ctr), ctr)
### 3
Why not just do it like this:
Python 3.x:
def amount_of_hashes(ctr):
while ctr > 0:
print('#', end = '')
ctr = ctr-1
Python 2.x:
def amount_of_hashes(ctr):
while ctr > 0:
print '#',
ctr = ctr-1
Counting the number in a list can be done like this:
def count_range_in_list(li, mini, maxi):
return len([i for i in li if mini <= i <= maxi])
Then making a number of hashes is even simpler. Just multiply a string containing the hash sign with a number.
print(ount_range_in_list(data, 0, 10)*'#')
Example in IPython:
In [1]: data = [90,30,13,67,85,87,50,45,51,72,64,69,59,17,22,23,44,25,16,67,85,87,50,45,51]
In [2]: def count_range_in_list(li, mini, maxi):
...: return len([i for i in li if mini <= i <= maxi])
...:
In [3]: print(count_range_in_list(data, 0, 10)*'#')
In [4]: print(count_range_in_list(data, 10, 20)*'#')
###
In [5]: print(count_range_in_list(data, 20, 30)*'#')
####
There are many ways to do this. One way is to use a for loop with range:
# Most basic
def count_range_in_list(li, min, max):
ctr = 0
hashes = ""
for x in li:
if min <= x <= max:
ctr += 1
hashes += "#"
print("There are {0} numbers = {1}".format(ctr, hashes))
# more declarative
def count_range_in_list(li, min, max):
nums = [x for x in li if min <= x <= max]
hashes = "".join(["#" for n in nums])
print("There are {0} numbers = {1}".format(len(nums), hashes))

The bowling game kata in pythonic python

I made an attempt to solve Uncle Bobs bowling game kata (http://www.butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata) but didn't really find a solution that felt pythonic enough.
This solution is more or less an adaptation of Martins C++ solution and uses array indexes to calculate scores for strikes and spares. It works but doesn't feel quite as pythonic as I would like it to be.
class Game():
def __init__(self):
self.rolls = []
def roll(self, pins):
self.rolls.append(pins)
def score_c(self):
total_score = 0
frame_index = 0
for frame in range(10):
if self.rolls[frame_index] == 10:
total_score += 10 + self.rolls[frame_index + 1] + self.rolls[frame_index + 2]
frame_index +=1
elif self.rolls[frame_index] + self.rolls[frame_index + 1] == 10:
total_score += 10 + self.rolls[frame_index + 1]
frame_index += 2
else:
total_score += self.rolls[frame_index] + self.rolls[frame_index + 1]
frame_index += 2
return total_score
I could have used convenience functions for strike and spare conditions, but you get the picture.
But I thought there must be a way to do it without accessing the rolls array directly though indexes. That feels like a very c-like way of doing it and incrementing frame_index directly definitely doesn't feel right in python. So I think there must be a neater way to do it. I made an attempt below which didn't really work for perfect games.
This one use a generator to provide frames which felt pretty neat but it also meant that 0 had to be added for strikes to make complete 2 roll frames.
class Game():
def __init__(self):
self.rolls = []
def _frame_iterator(self):
for i in range(0, 20, 2):
yield (self.rolls[i], self.rolls[i+1])
def roll(self, pins):
self.rolls.append(pins)
if pins == 10:
self.rolls.append(0)
def score(self):
total_score = 0
spare = False
strike = False
for frame in self._frame_iterator():
if spare:
total_score += frame[0]
spare = False
if strike:
total_score += frame[1]
strike = False
if frame[0] + frame[1] == 10:
spare = True
if frame[0] == 10:
strike = True
total_score += frame[0] + frame[1]
return total_score
My questions are basically, has anyone solved the bowling kata in Python in a different and more pythonic way than uncle bobs C++ solution? And suggestions how to improve on my attempt?
This is definitely a different approach (implementing most of the rules in roll(), instead of score()), and I think it's pretty pythonic too.
class Game(object):
def __init__(self):
self._score = [[]]
def roll(self, pins):
# start new frame if needed
if len(self._score[-1]) > 1 or 10 in self._score[-1]:
self._score.append([])
# add bonus points to the previous frames
for frame in self._score[-3:-1]:
if sum(frame[:2]) >= 10 and len(frame) < 3:
frame.append(pins)
# add normal points to current frame
for frame in self._score[-1:10]:
frame.append(pins)
def score(self):
return sum(sum(x) for x in self._score)
The main idea here is instead of storing all rolls in a single list, to make a list of frames that contains a list of rolls (and bonus points) for each frame.
What makes it pythonic is for example the generator expression in the score method.
Another pythonic example is the use of list slices. A previous version of middle part of roll() I did looked like:
for i in [2, 3]:
if len(self._score) >= i:
sum(self._score[-i][:2]) >= 10 and len(self._score[-i]) < 3:
self._score[-i].append(pins)
The elegant thing of the current version using a list slice is that you don't have to check whether the list is long enough to look 1 or 2 frames back. Moreover, you get a nice local variable (frame = self._score[-i]) for free, without having to dedicate a separate line for it.

Returning multiple integers as separate variables

I am trying to make a program that grabs 5 integers from the user, and then finds the average of them. I have it set up to take in the 5 numbers, but how do I return them all as separate variables so I can use them later on? Thanks!
def main():
x = 0
testScoreNumber = 1
while x < 5:
getNumber_0_100(testScoreNumber)
x += 1
testScoreNumber += 1
calcAverage(score1, score2, score3, score4, score5)
print(calculatedAverage)
def getNumber_0_100(testnumber):
test = int(input("Enter test score " + str(testnumber) + ":"))
testcount = 0
while testcount < 1:
test = int(input("Enter test score " + str(testnumber) + ":"))
if test > 0 or test < 100:
testcount += 1
return test
^Here is the problem, the everytime this function runs, I want it to return a different value to a different variable. Ex. test1, test2, test3.
def calcAverage(_score1,_score2,_score3,_score4,_score5):
total = _score1 + _score2 + _score3 + _score4 + _score5
calculatedAverage = total/5
return calculatedAverage
You need to store the result somewhere. It is usually (always?) a bad idea to dynamically create variable names (although it is possible using globals). The typical place to store the results is in a list or a dictionary -- in this case, I'd use a list.
change this portion of the code:
x = 0
testScoreNumber = 1
while x < 5:
getNumber_0_100(testScoreNumber)
x += 1
testScoreNumber += 1
to:
results = []
for x in range(5):
results.append( getNumber_0_100(x+1) )
which can be condensed even further:
results = [ getNumber_0_100(x+1) for x in range(5) ]
You can then pass that results list to your next function:
avg = get_ave(results[0],results[1],...)
print(avg)
Or, you can use the unpacking operator for shorthand:
avg = get_ave(*results)
print(avg)
It isn't the responsibility of the returning function to say what the caller does with its return value. In your case, it would be simple to let main have a list where it adds the return values. You could do this:
scores = []
for i in range(5):
scores.append(getNumber_0_100(i))
calcAverage(*scores)
Note that *scores is to pass a list as arguments to your calcAverage function. It's probably better to have calculateAverage be a general function which takes a list of values and calculates their average (i.e. doesn't just work on five numbers):
def calcAverage(numbers):
return sum(numbers) / len(numbers)
Then you'd call it with just calcAverage(scores)
A more Pythonic way to write the first part might be scores = [getNumber_0_100(i) for i in range(5)]
Python allows you to return a tuple, and you can unroll this tuple when you receive the return values. For example:
def return_multiple():
# do something to calculate test1, test2, and test3
return (test1, test2, test3)
val1, val2, val3 = return_multiple()
The limitation here though is that you need to know how many variables you're returning. If the number of inputs is variable, you're better off using lists.

"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