Python stack overlapped element cumulation - python

I want to cumulatively add element on Arraystack in Python
class StockManager:
__PROFIT = 0
def __init__(self, o_name, o_surname):
self.box = ArrayStack()
self._name = o_name
self._surname = o_surname
def buy_shares(self, company, number, buy_price):
StockManager.__PROFIT -= buy_price * number
n = 0
if len(self.box) < 2:
"""there is no overlapped elements when box has no element"""
self.box.push(company)
self.box.push(number)
else:
while n < len(self.box):
if self.box._data[n] == company:
"""every even index(n = 0, 2, 4, ...) refers to company name"""
"""every odd index(n = 1, 3, 5, ...), which is next to even index refers to number of buying"""
self.box._data[n + 1] += number
n += 2
elif self.box._data[n] != company:
""" if there's no overlapping, then just put the elements """
self.box.push(company)
self.box.push(number)
n += 2
return print(self.box._data)
and class Arraystack is like this:
class ArrayStack:
"""LIFO Stack implementation using a Python list as underlying storage."""
def __init__(self):
"""Create an empty stack."""
self._data = [] # nonpublic list instance
def __len__(self):
"""Return the number of elements in the stack."""
return len(self._data)
def is_empty(self):
"""Return True if the stack is empty."""
return len(self._data) == 0
def push(self, e):
"""Add element e to the top of the stack."""
self._data.append(e) # new item stored at end of list
def top(self):
"""Return (but do not remove) the element at the top of the stack.
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise AssertionError('Stack is empty')
return self._data[-1] # the last item in the list
def pop(self):
"""Remove and return the element from the top of the stack (i.e., LIFO).
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise AssertionError('Stack is empty')
return self._data.pop() # remove last item from list
def print_contents(self):
print("Stack content: {0}".format(self._data))
when I run stockmanager with
if __name__ == '__main__':
P = StockManager("A","B")
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("lg", 20, 100)
the result is
['hyundai', 20] => O.K
['hyundai', 40] => O.K
['hyundai', 60] => O.K
['hyundai', 60, 'lg', 40] => It should be ['hyundai', 60, 'lg', 20]
['hyundai', 60, 'lg', 60, 'lg', 40] => don't know why this result comes...
How can I handle this problem?

So, the problem lies in your while loop:
while n < len(self.box):
if self.box._data[n] == company:
"""every even index(n = 0, 2, 4, ...) refers to company name"""
"""every odd index(n = 1, 3, 5, ...), which is next to even index refers to number of buying"""
self.box._data[n + 1] += number
n += 2
elif self.box._data[n] != company:
""" if there's no overlapping, then just put the elements """
self.box.push(company)
self.box.push(number)
n += 2
Imagine we've run:
P = StockManager("A","B")
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
And so far, everything has worked as planned. Now, you try:
P.buy_shares("lg", 20, 100)
So: n == 0 and len(self.box) == 2, so we enter the loop.
The if condition fails, self.box._data[n] != 'lg', so we go to the elif block:
self.box.push(company)
self.box.push(number)
n += 2
Now, box == ['hyundai', 60, 'lg', 20] and n == 2. But wait! The loop condition is n < len(box), but len(box) == 4, so we enter the while-loop again! This time, the if conditions passes this time since self.box._data[2] == 'lg'.
So you execute the body of the if-block:
self.box._data[n + 1] += number
n += 2
Now, n == 4 and box == ['hyundai', 60, 'lg', 40]. This time, 4 < len(box) fails and we exit the loop and your function ends.
Now, a stack seems like the wrong data structure to me. It's clunky to have to increase the size by two. If you really wanted to do this, I would suggest an approach like
offset = 0
i = -2
for i in range(0, len(self.box), 2):
if self.box._data[n] == company:
break
else:
offset = 2
self.box.push(company)
self.box.push(0)
self.box._data[i + offset + 1] += number
But again, this is clunky. You would be better off using a dict for box, then the logic could be implemented simply as:
self.box[company] = self.box.get(company, 0) + 1
Or better yet, use a defaultdict
>>> from collections import defaultdict
>>> box = defaultdict(int)
>>> box
defaultdict(<class 'int'>, {})
>>> box['lg'] += 20
>>> box
defaultdict(<class 'int'>, {'lg': 20})
>>> box['lg'] += 20
>>> box
defaultdict(<class 'int'>, {'lg': 40})
>>> box['lg']
40

You are iterating over an entire list using indices; if the first company/number doesn't match the stock you are buying, it is automatically appended to the end of the list; then the next set of indices will point to the new company that was just appended so it adds the number. The elif is incorrect - you shouldn't append a new company/number pair till you have iterated through the whole list and didn't find it.
This is what you are doing
>>> a = ['a',1]
>>> n = 0
>>> comp, nbr = 'b', 2
>>> while n < len(a):
.... if a[n] == comp:
print('comp found at', n)
a[n+1] += nbr
n += 2
else:
print('n =', n, 'appending', comp)
a.append(comp)
a.append(nbr)
n += 2
n = 0 appending b
comp found at 2
>>>
This is what you could do to fix it:
>>> a = ['a',1]
>>> n = 0
>>> comp, nbr = 'b', 2
>>> while n < len(a):
found = False
if a[n] == comp:
print('comp found at', n)
a[n+1] += nbr
found = True
n += 2
>>> if not found:
a.append(comp)
a.append(nbr)
>>> a
['a', 1, 'b', 2]
>>>
But as suggested in the comments, you would probably be better off storing your purchase in a dictionary.

Related

sorting orders with mergesort incorrect output

I have to design an algorithm to sort a list of orders by selection time (t selection, finding the good in the warehouse and bringing it to the surface) plus shipping time (t shipping, constant). The customer orders can be retrieved (in the same order as placed) from a server database. You should expect between 100-10K elements.
The program takes as input a data-set of orders where the id, t selection, and t shipping are of type unsigned int, n is the number of orders and a space character.
id1, t selection1, t shipping1; ...; idn, t selectionn, t shippingn \n
The expected output is a space-separated list of the ids, sorted by t selection + t shipping and terminated by a new line \n.
Input: 1, 500, 100; 2, 700, 100; 3, 100, 100\n
Output: 3 1 2\n
I am trying to do it with merge sort, however my program returns
1 2 3/n instead of 3 1 2/n
I have provided my code below, could anyone help me out?
#!/usr/bin/env python3
import sys
class Order:
def __init__(self, id: int, selection_time: int, shipping_time: int):
self.id: int = id
self.selection_time: int = selection_time
self.shipping_time: int = shipping_time
def merge(left, right):
if not len(left) or not len(right):
return left or right
result = []
i, j = 0, 0
while len(result) < len(left) + len(right):
if left[i].shipping_time + left[i].selection_time < right[j].shipping_time + right[j].selection_time:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
if i == len(left) or j == len(right):
result.extend(left[i:] or right[j:])
break
return result
def sort(list):
if len(list) < 2:
return list
middle = int(len(list) / 2)
left = sort(list[:middle])
right = sort(list[middle:])
return merge(left, right)
if __name__ == '__main__':
'''
Retrieves and splits the input
'''
data = input()
data = data.split('; ')
order_list = []
for d in data:
id, selection_t, shipping_t = d.split(', ', 2)
order: Order = Order(int(id), int(selection_t), int(shipping_t))
order_list.append(order)
sort(order_list)
for order in order_list:
sys.stdout.write(str(order.id))
sys.stdout.write(" ")
The simplest (and probably least efficient) sorting algorithm is the Bubble sort. But the question says nothing about performance so it can be simplified like this:
class Order:
def __init__(self, ident, selection_time, shipping_time):
self._ident = ident
self._selection_time = selection_time
self._shipping_time = shipping_time
#property
def selection_time(self):
return self._selection_time
#property
def shipping_time(self):
return self._shipping_time
#property
def ident(self):
return self._ident
def merge(lst):
def comboval(order):
return order.selection_time + order.shipping_time
if len(lst) > 1:
mid = len(lst) // 2
left = lst[:mid]
right = lst[mid:]
merge(left)
merge(right)
i = j = k = 0
while i < len(left) and j < len(right):
if comboval(left[i]) < comboval(right[j]):
lst[k] = left[i]
i += 1
else:
lst[k] = right[j]
j += 1
k += 1
for _i in range(i, len(left)):
lst[k] = left[_i]
k += 1
for _j in range(j, len(right)):
lst[k] = right[_j]
k += 1
return lst
inval = '1, 500, 100; 2, 700, 100; 3, 100, 100'
orderlist = []
for order in inval.split(';'):
orderlist.append(Order(*map(int, order.split(','))))
print(*[order.ident for order in merge(orderlist)])
Output:
3 1 2
Note:
This is an in-place sort

Why is this list index out of range?

I am currently working on a school assignment from the AI department where I have to make a Genetic Algorithm. It is meant to solve the 8 Queens problem using a list called board, where each index is a column and the value in that index is the row. The algorithm itself works fine, but every time I try to run it, it crashes after the while loop reaches populationSize - 2 (in this case 18). The error that I get is about line:
child = reproduce(population[l], population[l + 1], nqueens)
and the error is:
Traceback (most recent call last):
File "nqueens1.py", line 370, in
main()
File "nqueens1.py", line 363, in main
genetic_algorithm(board)
File "nqueens1.py", line 291, in genetic_algorithm
child = reproduce(population[l], population[l + 1], nqueens)
IndexError: list index out of range
I am trying to understand what is going wrong, but I do not see why it would go out of range. Here is the code that I have so far:
Function Reproduce
def reproduce(boardX, boardY, nqueens):
boardChild = [-1] * nqueens
n = random.randint(0, (nqueens - 1)) #percentage of how much of one parent is reproduced and how much of the other parent
d = 0
for d in range(n): # the first n part of parent x
boardChild[d] = boardX[d]
s = d + 1
for s in range(nqueens) : # the last n-(len(board)-1) part of parent y
boardChild[s] = boardY[s]
return boardChild
Function Mutate
def mutate(child):
print('mutate')
boardMutated = [-1] * len(child)
newColumn = random.randint(0, len(child)-1)
newRow = random.randint(0, len(child)-1)
boardMutated[newColumn] = newRow
return boardMutated
Genetic Algorithm
def genetic_algorithm(board):
optimum = (len(board) - 1) * len(board) / 2
print('optimum:' + str(optimum))
nqueens = len(board)
populationSize = 20
population = []
for i in range(populationSize -1): #initializes first pooulation
population.append([])
for _ in range(nqueens):
population[i].append(random.randint(0, nqueens-1))
population[i].append(evaluate_state(population[i]))
if evaluate_state(population[i]) == optimum:
print("solved puzzle! 0")
print_board(population[i])
return
t = 0
while t != 1000:
population.sort(key=lambda x: x[nqueens -1 ]) #sorts the population from highest population size
for i in range(populationSize -1):
del population[i][-1]
newPopulation = [ [] for _ in range(populationSize -1) ]
newPopulation[0] = reproduce(population[1], population[0], nqueens) #
chance = random.randint(0, 100)
if chance < 5: # small chance that the child gets mutated
newPopulation[0] = mutate(newPopulation[0])
if evaluate_state(newPopulation[0]) == optimum:
print('if evaluate_state(child) == optimum:')
print("Solved puzzle! 1")
print_board(newPopulation[0])
return
if evaluate_state(newPopulation[0]) == optimum:
print("Solved puzzle! 2")
print('if evaluate_state(newPopulation[1]) == optimum:')
print_board(newPopulation[1])
return
l = 0
while l != (populationSize -1):
print(str(l))
child = reproduce(population[l], population[l + 1], nqueens) # reproduces the new generation
print_board(child)
if evaluate_state(child) == optimum:
print('if evaluate_state(child) == optimum:')
print("Solved puzzle! 3")
print_board(child)
return
chance = random.randint(0, 100)
if chance < 5: # small chance that the child gets mutated
child = mutate(child)
if evaluate_state(child) == optimum:
print('if evaluate_state(child) == optimum:')
print("Solved puzzle! 4")
print_board(child)
return
newPopulation[l] = child
l += 1
t += 1
All the print-statements were added to see which parts did execute and which did not execute. The code crashes as soon as the l reaches 18 here, which of course it should not. All help would be appreciated!
I think population only has 19 items, not 20; all the populations are initialized using range(populationSize - 1) which only has 19 numbers (from 0 to 18).
You can check this by also printing out len(population)

Fibonacci that takes a list of numbers and returns their fibonacci number

I am trying to implement a function that will print a number of fibonacci numbers. For example if my input was fibonacci([0,1,2,3], the output would be 0,1,1,2.
I am not sure how to proceed.
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
while True:
n.append(n)
print(fibonacci[5,10,11])
You can refactor your code a bit and get:
def fibonacci(lst):
def getTerm(n):
if n == 0:
return 0
elif n == 1:
return 1
return getTerm(n - 1) + getTerm(n-2)
return [getTerm(x) for x in lst]
Gives output:
>>> fibonacci([0,1,2,3])
[0, 1, 1, 2]
>>> fibonacci([5,10,11])
[5, 55, 89]
Avoiding redundant computations:
def fibonacci(indices):
fibs = {}
set_of_indices = set(indices)
f0 = fibs[0] = 0
f1 = fibs[1] = 1
for i in range(2,max(indices)+1):
f2 = f0+f1
if i in set_of_indices:
fibs[i] = f2
f0,f1=f1,f2
return [fibs[i] for i in indices]

Python: represent a number as a sum of prime numbers

I need to write an algorithm, that can represent a number as a min sum of prime numbers:
For example:
8 -> [2, 2, 2, 2], [3, 5], [2, 3, 3]
and I need get min len of this => 2
I've written the code, but it takes a lot of time, because it contains recursion. How can I change it to improve time?
import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []import sys
x = int(sys.stdin.readline())
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
return True
def decomposition(x):
result = []
for a in range(2, int(x/2 + 1)):
if x-a >= 2:
b = x - a
pair = [a, b]
result.append(pair)
return result
def f(elem):
list_of_mins = []
if is_prime(elem) == True:
return 1
else:
pairs = decomposition(elem)
print(pairs)
for a,b in pairs:
list_of_mins.append(f(a)+f(b))
return min(list_of_mins)
if str(int(x)).isdigit() and 2 <= int(x) <= 10 ** 9:
sum = []
print(f(x))
Your is_prime function only needs to test divisors up to pow(n, 0.5)+1. This means your code would be:
def is_prime(n):
for i in range(2, int(pow(n, 0.5)+1):
if n % i == 0:
return False
return True
This should speed your algorithm up significantly.
Here's a possible solution:
import math
class Foo():
def __init__(self, n):
self.n = n
self.primes = self.prime_sieve(n)
def prime_sieve(self, sieve_size):
sieve = [True] * sieve_size
sieve[0] = False
sieve[1] = False
for i in range(2, int(math.sqrt(sieve_size)) + 1):
pointer = i * 2
while pointer < sieve_size:
sieve[pointer] = False
pointer += i
primes = []
for i in range(sieve_size):
if sieve[i] == True:
primes.append(i)
return primes
def sum_to_n(self, n, size, limit=None):
if size == 1:
yield [n]
return
if limit is None:
limit = n
start = (n + size - 1) // size
stop = min(limit, n - size + 1) + 1
for i in range(start, stop):
for tail in self.sum_to_n(n - i, size - 1, i):
yield [i] + tail
def possible_sums(self):
for i in range(2, self.n):
result = list(self.sum_to_n(self.n, i))
result = (
[v for v in result if all([(p in self.primes) for p in v])])
if result:
yield result
def result(self):
for i in self.possible_sums():
return i
raise Exception("Not available result!")
if __name__ == '__main__':
obj = Foo(8)
print(list(obj.possible_sums()))
print('-' * 80)
try:
v = obj.result()
print("{} , length = {}".format(v[0], len(v[0])))
except Exception as e:
print(e)
Result:
[[[5, 3]], [[3, 3, 2]], [[2, 2, 2, 2]]]
--------------------------------------------------------------------------------
[5, 3] , length = 2

Python - how to distinguish between 2 objects of the same name in a list

So i'm making a genetic algorithm in python. The goal is for the "organism" to get to the top of the screen (x,20). I have a loop that creates the population which is a list of objects of type "Organism". Here is the code for the Organism class:
class Organism(object):
def __init__(self, genes,ID):
self.genes = genes
self.position = [0,0]
self.thisTime=str()
self.geneTranslation = []
self.ID=ID
def move(self,d):
if d == "f" or d == "forward":
self.position[1] += 1
elif d == "b" or d == "back":
self.position[1] -= 1
elif d == "r" or d == "right":
self.position[0] += 1
elif d == "l" or d == "left":
self.position[0] -= 1
print(self.position)
def isInContactWith(self,point):
point = list(point)
if self.position == point:
return True
else:
return False
def run(self):
for i in range(0,4):
if i == 0:
self.geneTranslation.extend(["f"] * self.genes[0])
elif i == 1:
self.geneTranslation.extend(["b"] * self.genes[1])
elif i == 2:
self.geneTranslation.extend(["r"] * self.genes[2])
elif i == 3:
self.geneTranslation.extend(["l"] * self.genes[3])
r.shuffle(self.geneTranslation)
for x in range(1,20):
self.thisTime = r.choice(self.geneTranslation)
self.move(self.thisTime)
As you can see, the genes specify the chance of a particular move. The problem is in the for loop that creates the population and runs it(ive added prints for debugging):
population = []
yValues={}
running = True
BestOrganism=Organism([25,25,25,25],0)
SecondOrganism=Organism([25,25,25,25],1)
for count in range(5):
for x in range(10):
a = lambda: r.randint(0, 3)
c = lambda: r.randint(-1, 1)
b = BestOrganism.genes
anOrganism = Organism(b,x)
anOrganism.genes[a()]+=c()
population.append(anOrganism)
for j in range(len(population)):
print("Organism " + str(population[j].ID) + str(population[j].genes))
population[j].run()
yValues[population[j].ID]=population[j].position[1]
if population[j].position[1]>=20:
print(population[j].genes)
running = False
break
BestOrganism=max(yValues)
for k in range(len(population)):
if population[k].ID==BestOrganism:
BestOrganism=population[k]
print(yValues[max(yValues)])
print(str(population)+"\n"+str(yValues)+"\n"+str(BestOrganism.genes))
population=[]
yValues={}
No errors pop up but, whenever I try to "mutate" a particular part of the organism's genes with anOrganism.genes[a()]=c(), it ends up mutating every organism in the list, even the ones not yet created, so that all of their genes are the exact same at the end (as seen in the final product). Why is python doing this?
It's because of this line: anOrganism = Organism(b,popPos).
So on the first iteration of the loop, you create an Organism and set the self.genes to b. Then you modify the .genes of that organism you just created.
When you iterate through the loop again, you are creating a new organism but with the same exact list, so it has the changes from the previous one.
Basically, there is only one b, and you are setting the .genes attribute of every organism to point to that single list. So any and everytime you change it, it changes for all of the organisms.
What you need to do is be sending in a copy of b to the constructor of Organism.
And then change the line anOrganism = Organism(b,popPos) to be
anOrganism = Organism(list(b), popPos)
The key is these lines:
b = BestOrganism.genes
anOrganism = Organism(b,popPos)
The list of genes will be shared by every organism created by that line. That is, anOrganism.genes is exactly the same object as BestOrganism.genes. So a change to BestOrganism.genes is seen in anOrganism.genes.
Python has an easy way to make a copy of a list, using "slicing". Change the line to this:
anOrganism = Organism(b[:],popPos)
Now anOrganism has its own genes, starting off identical to but still distinct from BestOrganism's genes.
Postscript:
Here is a simplified form, using literal ints instead of the random functions:
>>> class Organism(object):
... def __init__(self, genes, ID):
... self.genes = genes
... self.ID = ID
...
>>> zero = Organism([25,25,25,25],0)
>>> one = Organism(zero.genes, 1)
>>> two = Organism(zero.genes[:], 2)
>>> one.genes[2] += 5
>>> two.genes[3] += 7
>>> zero.genes
[25, 25, 30, 25]
>>> one.genes
[25, 25, 30, 25]
>>> two.genes
[25, 25, 25, 32]
>>>

Categories

Resources