Strange behavior with lists in Python - python

I have noticed that probability_matrix seems to become adapted_given_board despite never being assigned it.
def build_probability_matrix(self):
r = 0
p = -1
adapted_given_board = self.probability_matrix
print(self.game.board.given_board)
for i in range(len(self.game.board.given_board)-1):
p += 1
if self.game.board.given_board[i] == '\n':
r += 1
p = -1
else:
adapted_given_board[r][p] = self.game.board.given_board[i]
print(adapted_given_board)

This assignment:
adapted_given_board = self.probability_matrix
is a reference, not a copy. That is, you're creating a new name for self.probability_matrix, not a new list that has a copy of the contents.
So when you do:
adapted_given_board[r][p] = self.game.board.given_board[i]
it's the exact same as if you'd done:
self.probability_matrix[r][p] = self.game.board.given_board[i]
Be careful about trying to use copy to fix this, since you're working with two-dimensional lists; you might end up just pushing the problem down one level. There is such a thing as deepcopy, but here's one idea for a very minimal fix that just allocates new entries in the matrix before you assign to them:
def build_probability_matrix(self):
r = 0
p = -1
adapted_given_board = [[]] # start with one row that has zero cells
print(self.game.board.given_board)
for i in range(len(self.game.board.given_board)-1):
p += 1
adapted_given_board[r].append(None) # add a cell
if self.game.board.given_board[i] == '\n':
r += 1
adapted_given_board.append([]) # add a row
p = -1
else:
adapted_given_board[r][p] = self.game.board.given_board[i]
print(adapted_given_board)
Or you could simply append your new elements rather than assigning them by index...
def build_probability_matrix(self):
adapted_given_board = [[]]
print(self.game.board.given_board)
for element in self.game.board.given_board:
if element == '\n':
adapted_given_board.append([])
else:
adapted_given_board[-1].append(element)
print(adapted_given_board)

Related

Change Value in a list based on previous condition

I have a list of zeros and ones.
I am trying to replace the a value of 1 with a 0 if the previous value is also a 1 for a desired output as shown below.
list = [1,1,1,0,0,0,1,0,1,1,0]
new_list = [1,0,0,0,0,0,1,0,1,0,0]
I've tried using a for loop to no avail. Any suggestions?
How about this for loop:
list = [1,1,1,0,0,0,1,0,1,1,0]
new_list = []
ant=0
for i in list:
if ant ==0 and i==1:
new_list.append(1)
else:
new_list.append(0)
ant=i
question_list = [1,1,1,0,0,0,1,0,1,1,0]
new_list = [question_list[0]] # notice we put the first element here
for i in range(1, len(question_list) + 1):
# check if the current and previous element are 1
if question_list[i] == 1 and question_list[i - 1] == 1:
new_list.append(0)
else:
new_list.append(question_list[i])
The idea here is we iterate over the list, while checking the previous element.

concatenate strings in list if separated by 0s

Basically, whenever two strings in a list are separated by one or more zeroes, I want to join them together. ['a',0,'b'] => ["ab"].
I've tried yield and I really can't find a good way to say if you find a zero in the list, concatenate the next non-zero to the previous string.
I've used yield before, but I am just not approaching this correctly. Mind you, I don't insist on using yield, it just seemed the most likely approach to work, since a simple list comprehension won't do it.
Sample data and expected outputs:
dataexp = [
#input #expected
(["a"], ["a"]),
([0,0,"a","b",], ["a","b"]),
([0,"a","0",], ["a","0"]),
(["a",0,"b",], ["ab"]),
(["a",0,0,"b",], ["ab"]),
(["a","b",0], ["a","b"]),
(["a","b","c"], ["a","b","c"]),
(["a",0,"b",0, "c"], ["abc"]),
]
Some sample code
I just don't handle the concatenate logic correctly and only filter5 is a serious attempt.
dataexp = [
#input #expected
([0,0,"a","b",], ["a","b"]),
([0,"a","0",], ["a","0"]),
(["a",0,"b",], ["ab"]),
(["a",0,0,"b",], ["ab"]),
(["a","b",0], ["a","b"]),
(["a","b","c"], ["a","b","c"]),
(["a",0,"b",0, "c"], ["abc"]),
]
def filter0(li):
return [val for val in li if isinstance(val, str)]
def filter3(li):
pos = -1
len_li = len(li)
while pos < len_li-1:
pos += 1
if li[pos] == 0:
continue
else:
res = li[pos]
yield res
def filter5(li):
len_li = len(li)
pos = 2
p0 = p1 = None
while pos < len_li-1:
cur = li[pos]
if p0 in (0, None):
p0 = cur
pos +=1
continue
if cur == 0:
p1 = cur
pos += 1
continue
elif p1 == 0:
p0 = p0 + cur
pos += 1
continue
else:
p1 = cur
pos += 1
yield p0
if p0:
yield p0
if p1:
yield p1
for fn in [filter0, filter3, filter5]:
name = fn.__name__
print(f"\n\n{name}:")
for inp, exp in dataexp:
try:
got = list(fn(inp))
except (Exception,) as e:
got = str(e)
msg = "%-20.20s for %-80.80s \nexp :%s:\ngot :%-80.80s:" % (name, inp, exp, got)
if exp == got:
print(f"\n✅{msg}")
else:
print(f"\n❌{msg}")
I am generating html dynamically by pushing strings into a big List[str] then "\n".join() it. Most of the time, that's fine, browsers ignore whitespace, but Cypress does care about the \n in <td>xyz\n</td>. So, rather than changing everything, I thought I'd find a way to suppress the newline by using mylist.extend(0, "</td>"). But now I am just curious at the look-behind/ahead nature of this list problem. And, if you think Django or Jinja Templates are better suited, you'd be correct, except that this is generating Django Templates, rather than the final html.
I see no benefit of using a generator here. You can just keep track of the state determining your concat condition and either append or concatenate:
from typing import List, Literal, List
def process_list(l: List[Union[str, Literal[0]]]) -> List[str]:
result, concat = [], False
for e in l:
if e == 0:
concat = True
continue
if concat and result:
result[-1] += e
else:
result.append(e)
concat = False
return result

Why can I print this list of lists, but only append all up to and not including the last element of each iteration?

I can print the following list of lists fine, but when I append to an empty list, it skips the last on each iteration or gives me an index out of range error when I add one more.
This works:
ordered_results = []
temp = []
A = len(results[1])-2
i = 1
while i < len(results):
x = 0
y = 1
while x < A:
temp = [results[i][0], results[0][x], results[i][y]]
print(temp)
x+=1
y+=1
temp = [results[i][0], results[0][x], results[i][y]]
print(temp)
i+=1
ordered_results
Note: len(results[0]) = 240 and len(results[1] = 241
If you replace "print" with ordered_results.append(temp) it skips:
results[i][0], results[0][239], results[i][240]
each iteration.
(Note the code was expanded as I am messing around trying to figure this out, it was more compact before).

Error checking whether an element is in a list

i am trying to check whether certain elements are in a list, and to execute numerical update but i keep getting an error (below).
"if h2output[1] not in h1output == True or h2output[2] not in h1output == True:
IndexError: list index out of range"
doublewin = 0
h1output = []
h2output = []
h3output = []
v1output = []
v2output = []
v3output = []
d1output = []
d2output = []
for i in h1:
if i not in h1output:
h1output.append(i)
if len(h1output) == 2:
doublewin += 1
for i in h2:
if i not in h2output:
h2output.append(i)
if len(h2output) == 2:
if h2output[1] not in h1output == True or h2output[2] not in h1output == True:
doublewin += 1
As len(h2output)==2, it has only 2 positions, which in python starts at zero, therefore h2output[2] is out of bounds, index must be 0 or 1
You have hardcoded indexes in h2output[1] and h2output[2]. Either one of them is causing the issue. Please check the size of the list.
Remove True booleans in if condition as it is unnecessary.

Unbroken chain? Python iteration not being processed

So I've written a bit of code to stack integers in a list from the zeroth position. For some reason I cannot decipher, the while loop below is not being processed. I have followed all good style and syntax requirements that I know, and the while loop works when run by itself.
def row(line):
"""
Function that merges a single row or column.
"""
result_length = len(line)
print result_length
# Create a list of zeros the same length as the 'line' argument
pts_alloc = 0
dummy = 0
result = line
result[0:] = [pts_alloc for dummy in range(len(result))]
print result
#Iterate over the 'line' list looking for non-zero entries and
#stack them from 'result[0]'
line_count = 0
result_place = 0
while (line_count <= (len(line)-1)):
if (line[line_count] > 0):
result[result_place] = line[line_count]
print result
result_place += 1
line_count += 1
return result
print row([4, 0, 0, 5])
Is there a major error in this code that I've missed? Is there some syntax requirement that I am unaware of?
The problems seems to be this part:
result = line
result[0:] = [pts_alloc for dummy in range(len(result))]
By replacing a slice of result, with result = line, you are replacing that same slice in line, too, as result is just another reference to the same list, not a copy.
Since the slice is the entire list, anyway, just do:
result = [pts_alloc for dummy in range(len(result))]
Also, you are declaring a lot of unnecessary variables. You could shorten your code to this:
def row(line):
result = [0] * len(line)
result_place = 0
for x in line:
if x > 0:
result[result_place] = x
result_place += 1
return result
Or even this:
def row(line):
non_zero = [x for x in line if x > 0] # take non-zero values
return non_zero + [0] * (len(line) - len(non_zero)) # pad with zeros

Categories