Python: list.remove() behave wiredly [closed] - python

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 10 months ago.
Improve this question
def get_variables(cells):
domains = [1,2,3,4]
variables = {}
for cell in cells:
if(cell == "C11"):
variables[cell] = [1]
elif(cell == "C22"):
variables[cell] = [2]
elif(cell == "C33"):
variables[cell] = [3]
elif(cell == "C44"):
variables[cell] = [4]
else:
variables[cell] = domains
cells = ['C'+x+y for x in "1234" for y in "1234"]
variables = get_variables(cells)
csp = CSP(variables, constraints, assigned)
pprint(csp.variables)
csp.variables["C12"].remove(1)
print(csp.variables["C13"])
output:
{'C11': [1],
'C12': [1, 2, 3, 4],
'C13': [1, 2, 3, 4],
'C14': [1, 2, 3, 4],
'C21': [1, 2, 3, 4],
'C22': [2],
'C23': [1, 2, 3, 4],
'C24': [1, 2, 3, 4],
'C31': [1, 2, 3, 4],
'C32': [1, 2, 3, 4],
'C33': [3],
'C34': [1, 2, 3, 4],
'C41': [1, 2, 3, 4],
'C42': [1, 2, 3, 4],
'C43': [1, 2, 3, 4],
'C44': [4]}
[2, 3, 4]
It is supposed to remove 1 from "C12", instead it did it to "C13". Why is that? I guess something related to memory location? This really drives me crazy. Any suggestion would be appreciated!

I suppose that "C12" and "C13" don't contain different lists, but the same one. Meaning that no matter how you modify either one, the other will be affected in the same way.
To see this clearly, print csp.variables at the end instead of just "CSP12".
The mistake is this line:
variables[cell] = domains
Because every variable[cell] is given the same list. Which is a mutable type. So when it is modified, it will be modified in place.
To fix this you could give the cells copies or slices, which are different objects:
variables[cell] = domains.copy()
or
variables[cell] = domains[:]

try this
desired_key = 'C12'
for key in csp.keys():
if key == desired_key:
del csp[key][0]
print(csp)
``

Related

Generating lists from other lists while keeping the order [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 11 months ago.
Improve this question
I have a list in the form of [2, 1, 4, 3].
Is there a way to produce all of the possible sequences of the list values while keeping the same order? To further clarify, I am expecting something like this:
[1, 4, 3, 2],
[4, 3, 2, 1],
[3, 2, 1, 4],
[2, 1, 4, 3]
I would describe the problem as a case of "Reshuffling" but keeping the order constant, or imagining each of these sequences being circular, i.e. the final element in the list then becomes the first, etc. There are many ways to visualize this, hope it makes some sense.
>>> data = [4, 3, 2, 1]
[4, 3, 2, 1]
>>> l = len(data)
>>> for i in range(l):
... print(data[l - i:] + data[0:l - i])
...
[4, 3, 2, 1]
[1, 4, 3, 2]
[2, 1, 4, 3]
[3, 2, 1, 4]
Or if we want to capture them rather than print them:
[data[len(data)-i:] + data[0:len(data)-i] for i in range(len(data))]
Use this code:
l = [1, 4, 3, 2]
for element in l:
l.pop(0)
# removes the first element
l.append(element)
# appends the element at the end
print(l)
As I can see you want to remove the first element of the list and put it at the end.
You can use a deque to do something like this. Deque is a Doubly Eneded Queue and optimized for pop() and append() (in O(1) instead of O(n) for a list) and therefore well suited for a rotation that you are trying to do. Have a look at this blog post for more information.
from collections import deque
input_arr = [2, 1, 4, 3]
input_deque = deque(input_arr)
for i in range(len(input_arr)):
input_deque.rotate(-1)
print(list(input_deque))
Expected output:
[1, 4, 3, 2]
[4, 3, 2, 1]
[3, 2, 1, 4]
[2, 1, 4, 3]
Edit
As Chris commented, please keep the following in mind:
Be aware, rotating a deque is destructive. If you wanted to gather the rotated lists into a list, you'd want to be sure to put copies of the deque into that list, otherwise you'll end up with a list with four references to the same deque in the same state
— #Chris
To create a copy you can just call copy() on the created list which in my case would be done like this: list(input_deque).copy().

Finding changes made to lists [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
So I'm trying to find the items that went in and went out of a list before and after it changed
For example, at first my list is:
[1, 1, 2, 5, 7, 7]
And then a minute later it's:
[1, 2, 2, 5, 6, 7, 4]
How would I end up with 2 lists that show what items went out and which went in like so,
itemsOut = [1,7]
itemsIn = [2, 6, 4]
Position and length can change
You can use Counter from the built-in collections module:
>>> list1 = [1, 1, 2, 5, 7, 7]
>>> list2 = [1, 2, 2, 5, 6, 7, 4]
>>> from collections import Counter
>>> counter1 = Counter(list1)
>>> counter2 = Counter(list2)
>>> l_diff = counter1-counter2
>>> r_diff = counter2-counter1
>>> print(list(l_diff))
[1, 7]
>>> print(list(r_diff))
[2, 6, 4]
You could use something like this, to detect wich items changed.
old_arr = [1, 2, 2, 5, 7, 7]
new_arr = [1, 1, 2, 5, 7, 7]
items_out = []
for element in old_arr:
if new_arr.count(element) > 0:
new_arr.pop(new_arr.index(element))
else:
items_out.append(element)
print("Items out:", items_out)
print("Items in:", new_arr)

find occurrences of elements of a list in a list of list

i have a list [1, 2, 3]
i want to find number of times the elements of this list appears in a list of list:
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
occurrences = 4
What I’m doing currently is the following:
a = [1, 2, 3]
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
def get_count(a, b):
a = set(a)
return sum([a.issubset(x) for x in b])
print(get_count(a, lol))
This method works but is quite slow when I have 100s of 1000s of list to compare with a list of list (lol remains static!)
can we also preserve the "order" of the elements? there can be other elements in between. in this case occurrences will be 2 for the above case
Why not try:
testlist = lol ##Create a test list that we will work with
for i in range len(testlist): ##Start a loop that will repeat length of testlist times
if a in testlist: ##If/When it finds the first occurrence of the list a
Occurrences =+ 1 ##It adds 1 to the amount off occurences
Pos = testlist.index(a)
testlist.del(Pos) ##It deletes the instance from the list.
This should work

python random shuffle while loop

I'm trying to fill lists with permutations of the same initial list. I don't understand why the following is not working.
parts = [[],[]]
while len(parts[-1]) < 2:
newval = random.choice([[1,2,3,4],[5,6,7,8]])
for part in parts:
random.shuffle(newval)
part.append(newval)
Expected result would be something like:
[[[6,7,8,5],[1,3,4,2]],[[5,8,6,7],[4,2,3,1]]]
random.shuffle works in-place and consequently modifies newval. You have to make a copy when appending to part otherwise the same list (or list reference) is shuffled and stored in part.
import random
parts = [[],[]]
while len(parts[-1]) < 2:
newval = random.choice([[1,2,3,4],[5,6,7,8]])
for part in parts:
random.shuffle(newval)
part.append(newval[:])
print(parts)
possible outputs:
[[[3, 1, 2, 4], [5, 7, 6, 8]], [[1, 2, 4, 3], [6, 7, 5, 8]]]
[[[1, 3, 2, 4], [4, 2, 1, 3]], [[2, 4, 3, 1], [4, 3, 2, 1]]]
[[[7, 5, 6, 8], [3, 2, 4, 1]], [[8, 5, 6, 7], [1, 4, 3, 2]]]
Because in Python everything is reference. When you append the value to the array, in fact you add the reference to the place in memory where the value is stored.
Say, you have assigned the list to the first element. When on the next iteration you re-shuffle this list, you change the value in the memory. Thus, the value you will when accessing the element you appended on previous step is also changed.
To fix this, try appending copy.copy(newval) instead of just newval (do not forget to import copy)
Here is your code changed accordingly:
import copy
parts = [[],[]]
while len(parts[-1]) < 2:
newval = random.choice([[1,2,3,4],[5,6,7,8]])
for part in parts:
random.shuffle(newval)
part.append(copy.copy(newval))

All possible random tiles in 2048

I am trying to make a function that takes in a 2048 board (nested lists making a 4 by 4 grid), like this,
[[0, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]
Note: I know this isn't a realistic 2048 board, but I chose the example for simplicity
and the function should output a list of all of the places a random tile could appear(either a 2 or a 4)
For example, if I run the function on the board above, the output should be.
[[[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[4, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]]
So anywhere were there is a 0, we want to make one board where there 0 has been replaced by a 2 and another where it has been replaced by a 4.
Here is my code so far.
def all_rand_tiles(state):
states = []
changed = []
old_states = [None]
while old_states != states:
old_states = states
new_state = state
for row in range(4):
for tile in range(4):
if state[row][tile] == 0:
#AREA WITH PROBLEM BELOW THIS LINE
if [row, tile] not in changed:
new_state[row][tile] = 2
states.append(new_state)
new_state[row][tile] = 4
states.append(new_state)
changed.append([row, tile])
return states
The problem is that when I append the two different states in the final if statement, both states have the zero changed to a 4. So the output of the function if you run it on the board at the top will look like this.
[[[4, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[4, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]]
When I run new_state[row][tile] = 4 the state I just created is changed for having a 2 in it, to have a 4.
You can see the problem demonstrated if you print new_state before and after running new_state[row][tile] = 4 in the bad code area.
I am incredibly confused by this and I have no idea why I am having this stupid problem.
EDIT: Please try out your solutions before posting. I have given you the only function I am working with all_rand_tiles and so far I have been unable to fix the problem with any of the answers that have been presented.
you must create a copy of state and set it with new_state . because of you have a 2D array you must use deepcopy so change your code to this :
from copy import deepcopy
state=[[0, 0, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]
def all_rand_tiles(state):
states = []
changed = []
old_states = [None]
while old_states != states:
old_states = states
new_state = deepcopy(state)
for row in range(4):
for tile in range(4):
if state[row][tile] == 0:
if [row, tile] not in changed:
new_state[row][tile] = 2
states.append(new_state)
new_state = deepcopy(state)
new_state[row][tile] = 4
states.append(new_state)
new_state = deepcopy(state)
changed.append([row, tile])
return states
print all_rand_tiles(state)
DEMO:
[[[2, 0, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[4, 0, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[0, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]
[[0, 4, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]]]
The problem is that when you call states.append(new_state) you are appending a reference to new_state to the list, not a copy. Hence, any modifications made to the new_state object will affect all references to it. In order to get the behavior you want, you need to make your modification to new state and then append a copy of the list with that state to the new_states object. There are several ways to do this:
states.append(new_state[:]) # slice the list
states.append(copy.copy(new_state)) # use the copy function
states.append(list(new_state)) # explicitly construct a new list
I don't know Python specifically, but I've been programming about 20 years so my answer might actually make sense. You append the array twice, in the following code:
if [row, tile] not in changed:
new_state[row][tile] = 2
states.append(new_state) <--- appended the first time here
new_state[row][tile] = 4
states.append(new_state) <--- appended the second time here
changed.append([row, tile])
Is it appending the new_state array itself, or just a REFERENCE to the new_state array? If it's a reference to the new_state array, then both instances will be the same, since both references are referring to the latest version of new_state (which has a "4" in that row & tile).
If that's the cause, then the solution is to make an actual copy / clone of the array, or just copy each of the values in new_state individually to a new array, before you use states.append.
I believe you're running into the same issue as found in the question Strange behavior of python's append? . You're appending the same new_state twice, modifying the single copy each time.

Categories

Resources