Recursive function not refreshing a list inside a loop [duplicate] - python

This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 1 year ago.
I have the following class:
class Node:
def __init__(self, id, parent):
self.id = id
self.parent = parent
Some objects of the node class:
n0 = Node(0, None)
n1 = Node(1, n0)
n2 = Node(2, n1)
n3 = Node(3, n2)
And a recursive function to get an hierarchy tree:
def get_hierarchy(node, hierarchy_list=[]):
parent = node.parent
if parent:
hierarchy_list.append(parent)
return get_hierarchy(parent, hierarchy_list)
else:
return ', '.join(str(node.id) for node in reversed(hierarchy_list))
If I call the that function outside a loop it works as expected:
hierarchy = get_hierarchy(n3)
print(hierarchy)
# 0, 1, 2
But if I call that function inside a loop, the hierarchy_list varible is not refreshed on each loop:
for i in range(5):
nodes = [n0, n1, n2]
hierarchy = get_hierarchy(n3)
print(hierarchy)
# 0, 1, 2
# 0, 1, 2, 0, 1, 2
# 0, 1, 2, 0, 1, 2, 0, 1, 2
# 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2
# 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2
And if I force the hierarchy_list to be empty on each interaction, it works as expected:
for i in range(5):
nodes = [n0, n1, n2]
hierarchy = get_hierarchy(n3, []) # forcing to be empty
print(hierarchy)
# 0, 1, 2
# 0, 1, 2
# 0, 1, 2
# 0, 1, 2
# 0, 1, 2
Why python does not refreshes the hierarchy_list on each interaction since I am calling the get_hierarchy function outside get_hierarchy's scope, and if I force it to be a new list it works. And what is the reason for this behavior?

I think the reason is that you are using a mutable argument as the default value in the function, which is a bad idea. The list is initiated only once when the function is defined, not re-initiated every-time you call the function.
The default value of the function argument points to the same list everytime you call that function, so the append method keeps adding to the same list. When you force it to be an empty list, the argument points to a new empty list avoiding the issue you are having.
Have a look here for the same explanation.

Related

i have a python list, using map function is omitting the first zero of the list

I have this code in python, when I print the last line, it is giving an output "11100101100". I'm expecting the output,"011100101100". Notice that the output starts with 1 and not 0. although the variable gamma_sum_list is a list containing 12 digits and its starts with 0. The function somehow deletes the first zero automatically. The following is the exact gamma_sum_list:
def convert(list)
res = int("".join(map(str,list)))
return res
print(convert(gamma_sum_list))
Input:
[0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0]
Expected Output:
011100101100
Actual Output :
11100101100
Your issue is caused by converting the result of the join operation to an integer. Integers do not have leading zeroes. If you remove the int function you'll get a string with the leading zero you're after.
gamma_sum_list = [0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0]
def convert(my_list):
res = "".join(map(str,my_list))
return res
print(convert(gamma_sum_list))
Output:
011100101100
def convert(some_list):
res = "".join(map(str,some_list))
return res
gamma_sum_list = [0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0]
print(convert(gamma_sum_list))
or
conv = lambda x: ''.join(map(str, x))
print(conv(gamma_sum_list))
Consider that:
>>> "".join(list(map(str, [0, 1])))
'01'
How would you convert '01' to an integer? Well, its just 1.
>>> int("".join(list(map(str, [0, 1]))))
1
So you probably want to not convert the string to an int, just keep it as a str.

Implement Function Zero-One

Suppose a list of labels label_list = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2] (0 is class 0, 1 is class 1 and 2 is class 2) and X a list of lists (i.e. the features). Each list of X has a unique label from label_list associated.
How can I implement a function lambda in python to create the Function Zero-One?
EDIT
Here is an example of what X might look like :
X = [[0.4, 0.2, 0.232], [0.3434, 0.243985, 0.9834], [0.3434, 0.345, 0.198459], [0.34324, 0.909834, 0.93849], [0.983498, 0.9384938, 0.983489], [0.768759, 0.9384, 0.897629], [0.14739, 0.872847, 0.62874], [0.6874, 0.87387, 0.83787], [0.8723874, 0.873764, 0.7527648], [0.762, 0.2648, 0.768738]]
Be aware that C is the associated class, i is the number of the class (i.e. either 0, 1 or 2) and t is the t-th vector/list of X.

Python: how to implement crossover of two integers?

I'm experimenting with a genetic search algorithm and after building the initial population at random, and then selecting the top two fittest entries, I need to 'mate' them (with some random mutation) to create 64
'children'. The crossover part, explained here:
https://towardsdatascience.com/introduction-to-genetic-algorithms-including-example-code-e396e98d8bf3
seems easy to follow, but I can't seem to figure out how to implement it in Python. How can I implement this crossover of two integers?
def crossover(a, b, index):
return b[:index] + a[index:], a[:index] + b[index:]
Should be quite a bit faster than James' solution, since this one lets Python do all the work!
Here is a function called crossover that takes two parents and a crossover point. The parents should be lists of integers of the same length. The crossover point is the point before which genes get exchanged, as defined in the article that you linked to.
It returns the two offspring of the parents.
def crossover(a, b, crossover_point):
a1 = a[:]
b1 = b[:]
for i in range(crossover_point):
a1[i], b1[i] = b1[i], a1[i]
return [a1, b1]
And here is some code that demonstrates its usage. It creates a population consisting of two lists of length 10, one with only zeros, and the other with only ones. It crosses them over at point 4, and adds the children to the population.
def test_crossover():
a = [0]*10
b = [1]*10
population = [a,b]
population += crossover(a,b,4)
return population
print (test_crossover())
The output of the above is:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
]

How to retain values appended to a python list

Please I need help with this code.I want mylist to retain values appended to it next time the function 'no_repeat_rule' is called. I'm pretty new to python. My code is below:
def no_repeat_rule(play_board):
mylist = list()
if seeds_left(play_board) == 2 and sum(play_board[:6])== 1:
mylist.append(play_board)
return mylist
Output of this code (in part) is:
...
[[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]]
Player 1 chose cup 0
[[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]]
Player 2 chose cup 6
[[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]]
...
what I want the function 'no_repeat_rule' to do is to grow mylist each time a player plays. I don't know if this is clear enough to get help?
The simplest thing to do would be to add another parameter in the function defintion, such that it looks like:
def no_repeat_rule(play_board, aList):
Before you call the function, declare a list outside of the function. Set this equal to the result of the function, and pass it as a parameter whenever you call the function. For instance:
x = list()
def no_repeat_rule(play_board, aList):
myList = aList
if seeds_left(play_board) == 2 and sum(play_board[:6])== 1:
myList.append(play_board)
return myList
x = no_repeat_rule(someBoardHere, x)
I believe this should work if I understand what you're asking. If not, please respond and I'll try something else.
what do you need is an object which is associated with the function. It calls attribute. It is very handy in python.
Your code may look like this:
def no_repeat_rule(play_board):
if not hasattr(no_repeat_rule,"mylist"):
no_repeat_rule.mylist = []
if seeds_left(play_board) == 2 and sum(play_board[:6])== 1:
no_repeat_rule.mylist.append(play_board)
return no_repeat_rule.mylist
I couldn't check this code, but it should work for local atributes. BTW it is for python 2.7

adding tuples to a list in an if loop (python)

I'm working in python with symbulate for a probability course and running some simulations.
Setup: Two teams, A and B, are playing in a “best of n” game championship series, where n is an odd number. For this example, n=7, and the probability team A wins any individual game is 0.55. Approximate the probability that Team A wins the series, given that they win the first game.
Here is what I've got so far, which I think is along the right lines:
model = BoxModel([1, 0], probs=[0.55, .45], size=7, replace=True)
test = model.sim(10000)
for x in range(0,10000):
test1 = test[x]
if test1[0] == 1:
print (test1)
test1
The last two lines are where I'm having my difficulty. This 'for' and 'if' combination makes it so only the inputs that start with a '1' (i.e. Team A winning the first game) are displayed. I need to save these inputs into a table so that I can run some further testing on it.
How do I input the value of test1 into a table while those loops are running? Currently, test1 only outputs the x=10,000th value.
Edit: The "test" yields a list, 0-10000, of all the possible game outcomes. I need a list that only has the game outcomes that start with a "1".
Edit2: Output of "test" (before I run a "for" or "if") look like:
Index Result
0 (1, 1, 1, 0, 0, 1, 1)
1 (0, 1, 0, 1, 1, 0, 0)
2 (1, 1, 1, 1, 0, 1, 0)
3 (0, 0, 1, 1, 1, 1, 1)
4 (0, 0, 0, 0, 0, 0, 0)
5 (1, 1, 0, 1, 0, 0, 1)
6 (0, 0, 1, 0, 1, 1, 1)
7 (0, 1, 0, 0, 0, 0, 1)
8 (1, 1, 0, 1, 0, 1, 0)
... ...
9999 (1, 1, 0, 1, 0, 0, 0)
I need a "test' (or another variable) to contain something that looks EXACTLY like that, but only contains lines that start with "1".
So you're looking to store the results of each test? Why not store them in a list?
test1_results = []
for x in range(0,10000):
test1 = test[x]
# check if first element in sequence of game outcomes is a win for team A
if test1[0] == 1: # or '1' if you're expecting string
test1_results.append(test1)
You can the run print(test1_results) to print the entire list of results, but if you want to print the first n results, do print(test1_results[:n]).
If you want your if statement in there, you will have to slightly adjust the placement. What does your test object look like? Could you give us a small sample?
edit: updated if statement to reflect comment below
Based on your comment:
results_that_start_with_one = []
for result in test:
result_string = str(result)
if result_string[0] == "1":
results_that_start_with_one.append(result_string)
This iterates through each of your results in the list "test". It convert each to a string (i'm assuming they are some numeric value). It then takes the first character in the string, and asks if its a 1.

Categories