Trouble with zip when running for loop monte carlo sim; python - python

Working in python 2.7.
I'm sure the code is a little unwieldy, but I'll try to explain it as simply as I can.
I have two lists:
T = [[1,0], [1,0], [0,5]]
S = [[1], [3], [2]]
I need to add the corresponding value from B to the end of the corresponding list in T, so using zip, I put them together.
I then calculate the result of the first value of each list subtracted from the third, and append that value using another zip function.
So when I run my function, the T variable now looks like [[1,0,1,0], [1,0,3,-2], [0,5,2,-2]].
I then have a series of if statements that if certain values are higher or lower than others, the list returns win, loss, or tie.
I would like to simulate the results of my function (starterTrans) multiple times. The problem is that when I use:
def MonteCarlo(T, S, x):
for i in range(0, x):
starterTrans(T, S)
For each simulation I am getting a different version of T. So the first time through the simulation T has the appropriate number of elements in each list (four), but after each run through, more and more variables are added.
I need a way to lock T to it's original four variables no matter how many times I want to use it. And I'm struggling finding a way to do so. Any ideas?
I know my code is convoluted, but here it is if it helps anyone follow my attempt to describe my problem:
def starterTrans(team, starter):
wins = 0
losses = 0
nd = 0
random.shuffle(team)
for t, s in zip(team, starter):
t.extend(s)
score_add(team, exit_score(team, starter))
length = len(starter)
for i in range(0, length):
if team[i][4] > 0 and (team[i][1] > -team[i][4]) and team[i][2] >= 5:
wins += 1
elif team[i][4] < 0 and (team[i][1] <= -team[i][4]):
losses += 1
elif (team[i][4] <= 0 and team[i][1] >= -team[i][4]):
nd += 1
return wins, losses, nd
def score_add(team, exit_scores):
for t, e in zip(team, exit_scores):
t.append(e)
return team
def exit_score(team, starter):
exit_scores = []
length = len(starter)
for i in range(0, length):
score = team[i][0]-team[i][3]
exit_scores.append(score)
return exit_scores
def MonteCarlo(team, starter, x):
for i in range(0, x):
starterTrans(team, starter)
Thanks for any help.

I think you just need to change this:
def MonteCarlo(T, S, x):
for i in range(0, x):
starterTrans(T, S)
to this:
def MonteCarlo(T, S, x):
for i in range(0, x):
starterTrans(T[:], S)
This will pass a copy of T to starterTrans(..) instead of the original list. If you're editing the elements of T in starterTrans(..) this will not help. Here you would need a deep copy. Have a look here for the difference between shallow and deep copies: What is the difference between a deep copy and a shallow copy?.

Change the last line to starterTrans(team[:], starter). That will pass in a copy of team, leaving the original intact.

Related

def count_dominators(items). Finding Dominators in a List. How to make this more efficient?

I was given a problem where I need to find the number of dominators in a list. Here is a description of the problem. And here is what I came up with: my solution.
From what I can tell, the code works but when it gets to very large numbers, like the final test, it takes way to long to return anything. I'm pretty sure there's a way to reduce this into a single loop but I have no idea how to do this.
there is a linear solution I hope u can use it.
in this way, the pointer move from end to start and if find a new maximum, the counter(n) plus one.
def count(lst):
if lst == []:
return 0
lst.reverse()
max_i = lst[0]
n = 1
for x in lst:
if x > max_i:
max_i = x
n += 1
return n

Easiest way to classify these values?

I have a list of layer heights that I want to sort various z values into. The list should remain in descending order and the function should return the index of the layer the z value belongs to.
For example, for the layers = [10,9,8,7] the value 9 should be returned as 1 since that's the index of its layer, the value 8.5 should also be returned as 1, the value 8 should return 2, 7.9 returns 2, and so on.
The function I wrote raises an error when it looks for an index outside the length of the list for the last layer.
def less_than(layers,z):
index = 0
current = layers[index]
while current>z:
index += 1
current = layers[index]
return(index-1)
So, what's the best method for producing such a function with these properties?
Here's a solution using bisect:
import bisect
class ReverseAccessor:
def __init__(self, ls):
self.ls = ls
def __getitem__(self, item):
return self.ls[-(item) - 1]
def __len__(self):
return len(self.ls)
def less_than(layers, z):
index = len(layers) - (bisect.bisect(ReverseAccessor(layers), z)) - 1
if layers[index + 1] == z:
return index + 1
return index
This is a bit more complicated than your solution, but will theoretically perform better when the list gets large. We define a custom object that holds a reference to the original list and translates item accesses into their reversed form. That way, we can retain the O(log n) complexity of bisect.
Your function is fine, you just need to check that you are not trying to access elements that don't exist (I also simplified it a little bit):
def less_than(layers, z):
index = 0
while index < len(layers) and layers[index] > z:
index += 1
return index - 1
Apart from the index error this should behave exactly like your function.
If your list of layers is not that big and you don't really care about the O(logN) of bisect, here's a very simple O(N) solution:
import math
layers.index(math.ceil(z))
ceil is rounding z up, and then we use built-in method of list to find the index of the item.
You can substitute ceil(z) for int(z + 0.5) if you don't want any imports.
Solution based on np.where:
import numpy as np
layers = [10,9,8,7]
def less_than(layers, z):
return np.max(np.where(np.array(layers)>=z))
Example:
less_than(layers, 8.5)
output:
1

My python recursive function won't return and exceeds maximum recursive depth

I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)

How to find number of ways that the integers 1,2,3 can add up to n?

Given a set of integers 1,2, and 3, find the number of ways that these can add up to n. (The order matters, i.e. say n is 5. 1+2+1+1 and 2+1+1+1 are two distinct solutions)
My solution involves splitting n into a list of 1s so if n = 5, A = [1,1,1,1,1]. And I will generate more sublists recursively from each list by adding adjacent numbers. So A will generate 4 more lists: [2,1,1,1], [1,2,1,1], [1,1,2,1],[1,1,1,2], and each of these lists will generate further sublists until it reaches a terminating case like [3,2] or [2,3]
Here is my proposed solution (in Python)
ways = []
def check_terminating(A,n):
# check for terminating case
for i in range(len(A)-1):
if A[i] + A[i+1] <= 3:
return False # means still can compute
return True
def count_ways(n,A=[]):
if A in ways:
# check if alr computed if yes then don't compute
return True
if A not in ways: # check for duplicates
ways.append(A) # global ways
if check_terminating(A,n):
return True # end of the tree
for i in range(len(A)-1):
# for each index i,
# combine with the next element and form a new list
total = A[i] + A[i+1]
print(total)
if total <= 3:
# form new list and compute
newA = A[:i] + [total] + A[i+2:]
count_ways(A,newA)
# recursive call
# main
n = 5
A = [1 for _ in range(n)]
count_ways(5,A)
print("No. of ways for n = {} is {}".format(n,len(ways)))
May I know if I'm on the right track, and if so, is there any way to make this code more efficient?
Please note that this is not a coin change problem. In coin change, order of occurrence is not important. In my problem, 1+2+1+1 is different from 1+1+1+2 but in coin change, both are same. Please don't post coin change solutions for this answer.
Edit: My code is working but I would like to know if there are better solutions. Thank you for all your help :)
The recurrence relation is F(n+3)=F(n+2)+F(n+1)+F(n) with F(0)=1, F(-1)=F(-2)=0. These are the tribonacci numbers (a variant of the Fibonacci numbers):
It's possible to write an easy O(n) solution:
def count_ways(n):
a, b, c = 1, 0, 0
for _ in xrange(n):
a, b, c = a+b+c, a, b
return a
It's harder, but possible to compute the result in relatively few arithmetic operations:
def count_ways(n):
A = 3**(n+3)
P = A**3-A**2-A-1
return pow(A, n+3, P) % A
for i in xrange(20):
print i, count_ways(i)
The idea that you describe sounds right. It is easy to write a recursive function that produces the correct answer..slowly.
You can then make it faster by memoizing the answer. Just keep a dictionary of answers that you've already calculated. In your recursive function look at whether you have a precalculated answer. If so, return it. If not, calculate it, save that answer in the dictionary, then return the answer.
That version should run quickly.
An O(n) method is possible:
def countways(n):
A=[1,1,2]
while len(A)<=n:
A.append(A[-1]+A[-2]+A[-3])
return A[n]
The idea is that we can work out how many ways of making a sequence with n by considering each choice (1,2,3) for the last partition size.
e.g. to count choices for (1,1,1,1) consider:
choices for (1,1,1) followed by a 1
choices for (1,1) followed by a 2
choices for (1) followed by a 3
If you need the results (instead of just the count) you can adapt this approach as follows:
cache = {}
def countwaysb(n):
if n < 0:
return []
if n == 0:
return [[]]
if n in cache:
return cache[n]
A = []
for last in range(1,4):
for B in countwaysb(n-last):
A.append(B+[last])
cache[n] = A
return A

Sum nested lists with recursive function

Hi i have a nested list which i should sum it from recursive function
how can i do that?
my solution didn't work
def n_l_sum(n):
s=0
for i in n:
if i==list:
s+=i
else:
s+=n_l_s(n)
return s
use the isinstanceof function instead of using the ==
def summer(lst):
if not isinstance(lst, list) : return lst
sum = 0
for x in lst:
sum += summer(x)
return sum
def main():
a= [1,2,3, [5,6]]
print(summer(a))
Recursion can be quite difficult to grasp at first; because it can be very intuitive to conceptualize but an pain to implement. I will try to explain my answer as thoroughly as possible so that you understand what exactly is happening:
def n_l_sum(n,i):
s=0 #somewhere to store our sum
lenLst= len(n)
cur = n[i] #sets current element to 'cur'
if lenLst-1-i < 1: #this is the base case
return cur
else:
s = n_l_sum(n,i+1)+cur #where the actual iteration happens
print(s) #give result
return s
n=[6,4]
n_l_sum(n,0)
The Base Case
The first important thing to understand is the base case this gives the recursion a way of stopping.
For example without it the function would return an IndexError because eventually n_l_sum(n,i+1) would eventually go over the maximum index. Therefore lenLst-1-i < 1 stops this; what it is saying: if there is only one element left do this.
Understanding Recursion
Next, I like to think of recursion as a mining drill that goes deep into the ground and collects its bounty back on the way up to the surface. This brings us to stack frames you can think of these as depths into the ground (0-100 m, 100-200 m). In terms of programming they are literal frames which store different instances of variables. In this example cur will be 4 in frame 1 then 6 in frame 2.
once we hit the base case we go back up through the frames this is where s = n_l_sum(n,i+1)+cur does the legwork and calculates the sum for us.
If you are still struggling to understand recursion try and run this code through http://www.pythontutor.com/visualize.html#mode=edit to see what is happening on a variable level.
def n_l_s(n):
s=0
for i in n:
if type(i) != type([]):
s+=i
else:
s+=n_l_s(i)
return s
n=[3, -1, [2, -2], [6, -3, [4, -4]]]
print(n_l_s(n))
output:
5
The functional way would be to to this:
def list_sum(l):
if not isinstance(l, list): # recursion stop, l is a number
return l
# do list_sum over each element of l, sum result
return sum(map(list_sum, l))

Categories