list.copy() not creating an true copy [duplicate] - python

This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 3 years ago.
I'm trying to write a little bit of code to complete an exercise on codewars link
Part of what I want to do is loop through a list of lists that are representing the sudoku grid and replace 0's with a list of possible numbers.
My problem is that even when I use list.copy() to hold the original puzzle any changes I make to the original list (not the copy) still changes the copy.
How can this be happening?
Below is my code:
def sudoku(puzzle):
# copy the puzzle to be able to save original positions that are changeable
pc = puzzle.copy()
puzzle = pns(puzzle)
return puzzle
def pns(puzzle):
for y in range(len(puzzle)):
for x in range(len(puzzle[0])):
pn = set(range(1,len(puzzle) + 1))
for row_idx in range(len(puzzle)):
for col_idx in range(len(puzzle[row_idx])):
skip_bool = True
if puzzle[y][x] != 0 and type(puzzle[y][x]) == type(1):
skip_bool = False
if row_idx == y and col_idx != x and type(puzzle[row_idx][col_idx]) != type([0]):
if puzzle[row_idx][col_idx] in pn:
pn.remove(puzzle[row_idx][col_idx])
if col_idx == x and row_idx != y and type(puzzle[row_idx][col_idx]) != type([0]):
if puzzle[row_idx][col_idx] in pn:
pn.remove(puzzle[row_idx][col_idx])
pn = list(pn)
if len(pn) == 1:
puzzle[y][x] = pn[0]
elif len(pn) == 0:
puzzle[y][x] = False
elif skip_bool:
puzzle[y][x] = pn
return puzzle
Expected output from:
print(pc)
print(puzzle)
[5, 3, 0, 0, 7, 0, 0, 0, 0]
[6, 0, 0, 1, 9, 5, 0, 0, 0]
[0, 9, 8, 0, 0, 0, 0, 6, 0]
[8, 0, 0, 0, 6, 0, 0, 0, 3]
[4, 0, 0, 8, 0, 3, 0, 0, 1]
[7, 0, 0, 0, 2, 0, 0, 0, 6]
[0, 6, 0, 0, 0, 0, 2, 8, 0]
[0, 0, 0, 4, 1, 9, 0, 0, 5]
[0, 0, 0, 0, 8, 0, 0, 7, 9]
[5, 3, [1, 2, 4, 6, 9], [2, 6, 9], 7, [1, 2, 4, 6, 8], [1, 4, 6, 8, 9], [1, 2, 4, 9], [2, 4, 8]]
[6, [2, 4, 7, 8], [2, 3, 4, 7], 1, 9, 5, [3, 4, 7, 8], [2, 3, 4], [2, 4, 7, 8]]
[[1, 2, 3], 9, 8, [2, 3, 5, 7], [3, 4, 5], [1, 2, 4, 7], [1, 3, 4, 5, 7], 6, [2, 4, 7]]
[8, [1, 2, 4, 5, 7], [1, 2, 4, 5, 7, 9], [2, 5, 7, 9], 6, [1, 2, 4, 7], [1, 4, 5, 7, 9], [1, 2, 4, 5, 9], 3]
[4, [2, 5, 7], [2, 5, 6, 7, 9], 8, 5, 3, [6, 7, 9], [2, 9], 1]
[7, [1, 4, 5, 8], [1, 3, 4, 5, 9], [3, 5, 9], 2, [1, 4, 8], [1, 3, 4, 5, 8, 9], [1, 3, 4, 5, 9], 6]
[[1, 3, 9], 6, [1, 3, 4, 5, 7, 9], [3, 5, 7, 9], [3, 4], [1, 4, 7], 2, 8, [4, 7]]
[[2, 3], [2, 7, 8], [2, 3, 6, 7], 4, 1, 9, [3, 6, 7, 8], [2, 3], 5]
[[1, 2, 3], [1, 2, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 5, 6], 8, [1, 2, 4, 6], [1, 3, 4, 5, 6], 7, 9]
What I actually get back is 2 copies of the second list.

For nested structures, .copy() only will create a copy of the top-level objects, but the references contained within will still be the same references.
You probably want copy.deepcopy().

Related

How to go through each sub-grid 3x3 using for loop?

I have been working on sudoku. The size of the original grid is 9x9 (a list containing 9 lists, each of which is a row). I need to check whether the digits only occur once per 3x3 sub-grid. In order to do that I have to go through each sub-grid using for loop (I think). So, I spent quite some time trying to do that, but I cannot seem to understand how exactly do it using for loop.
example_of_full_grid = [[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 0, 3, 4, 9],
[1, 0, 0, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 0, 2, 0],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 0, 1, 5, 3, 7, 2, 1, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 0, 0, 4, 8, 1, 1, 7, 9]]
Is it possible to use numpy for you?
The code below loops over all 9 subgrids.
import numpy as np
grid = np.array([[5, 3, 4, 6, 7, 8, 9, 1, 2],
[6, 7, 2, 1, 9, 0, 3, 4, 9],
[1, 0, 0, 3, 4, 2, 5, 6, 0],
[8, 5, 9, 7, 6, 1, 0, 2, 0],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 0, 1, 5, 3, 7, 2, 1, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 0, 0, 4, 8, 1, 1, 7, 9]])
for i in range(0,9,3):
for j in range(0,9,3):
print(grid[i:i+3,j:j+3])
This has to be changed for a list. See below:
subgrid = []
for i in range(0,9,3):
row_3x3 = []
for j in range(0,9):
row_3x3.append(example_of_full_grid[j][i:i+3])
for j in range(0,9,3):
subgrid.append(row_3x3[j:j+3])
print(row_3x3[j:j+3])

Select and compare every element in a column-list

I am trying to solve this puzzle question:
There is only one five-digit number n, such that every one of the following ten numbers share exactly one digit in common in the same position as n. Find n.
I'm trying to get like this:
https://i.stack.imgur.com/hufIc.jpg
For each column, selects every element and compares it along the column if it matches the same number. And then, appends it to get which number were matched on every column.
should i add if's in here:
L = [[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]]
for c in range(10):
for r in range(5):
print(L[c][r], end=' ')
print()
The easiest way I can think of is to get all the values of a column in a variable and then check if any value occurs more than once. The solution would look something like:
L = [
[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]
]
for r in range(5):
val = [L[c][r] for c in range(10)]
for i in range(10):
if val[i] in val[:i]:
print(val[i], end=" ")
break
else:
print(0, end=" ")
print()
L = [
[0, 1, 2, 6, 5],
[1, 2, 1, 7, 1],
[2, 3, 2, 5, 7],
[3, 4, 5, 4, 8],
[4, 5, 9, 7, 0],
[5, 6, 2, 3, 6],
[6, 7, 3, 2, 4],
[7, 8, 0, 8, 4],
[8, 9, 8, 7, 2],
[9, 9, 4, 1, 4]
]
for col_index in range(5):
col= [row[col_index] for row in L]
duplicate = [x for x in col if col.count(x) > 1]
if len(duplicate) == 0:
print(0, end=" ")
else:
print(duplicate[0], end=" ")
print()

Advanced List Coding using multiple lists

So we are given two lists.
groups = [[0,1],[2],[3,4,5],[6,7,8,9]]
A = [[[0, 1, 6, 7, 8, 9], [0, 1, 6, 7, 8, 9]], [[2]], [[3, 4, 5, 6, 7, 8, 9], [3, 4, 5, 6, 7, 8, 9], [3, 4, 5, 6, 7, 8, 9]], [[0, 1, 3, 4, 5, 6, 8, 9], [0, 1, 3, 4, 5, 7, 8, 9], [0, 1, 3, 4, 5, 6, 7, 8, 9], [0, 1, 3, 4, 5, 6, 7, 8, 9]]]
How do we replace the the elements in A with their corresponding indexes in groups: i.e., replace the 0 and 1 in A with 0, the 2 in A with 1, the 3, 4 and 5 with 2 and so on.
Output:
A = [[[0, 0, 3, 3, 3, 3], [0, 0, 3, 3, 3, 3]], [[1]], [[2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3]], [[0, 0, 2, 2, 2, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3, 3]]]
create a dictionry which store the index value for those numbers and then for those number in list A add the index
groups = [[0,1],[2],[3,4,5],[6,7,8,9]]
A = [[[0, 1, 6, 7, 8, 9], [0, 1, 6, 7, 8, 9]], [[2]], [[3, 4, 5, 6, 7, 8, 9], [3, 4, 5, 6, 7, 8, 9], [3, 4, 5, 6, 7, 8, 9]], [[0, 1, 3, 4, 5, 6, 8, 9], [0, 1, 3, 4, 5, 7, 8, 9], [0, 1, 3, 4, 5, 6, 7, 8, 9], [0, 1, 3, 4, 5, 6, 7, 8, 9]]]
from collections import defaultdict
dic = defaultdict(int)
for i in range(len(groups)):
for j in groups[i]:
dic[j]=i
for i in A:
for j in i:
for l in range(len(j)):
j[l] = dic[j[l]]
output
[[[0, 0, 3, 3, 3, 3], [0, 0, 3, 3, 3, 3]],
[[1]],
[[2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3]],
[[0, 0, 2, 2, 2, 3, 3, 3],
[0, 0, 2, 2, 2, 3, 3, 3],
[0, 0, 2, 2, 2, 3, 3, 3, 3],
[0, 0, 2, 2, 2, 3, 3, 3, 3]]]
Even though there is no attempt from your side, here you go :
def f(l,i):
for k in l:
if i in k:
return l.index(k)
output_ = [[[f(groups,n) for n in a0] for a0 in a] for a in A]
Output :
[[[0, 0, 3, 3, 3, 3], [0, 0, 3, 3, 3, 3]], [[1]], [[2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3], [2, 2, 2, 3, 3, 3, 3]], [[0, 0, 2, 2, 2, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3, 3], [0, 0, 2, 2, 2, 3, 3, 3, 3]]]
try this:
def replace_items(i, inner_list, *lists):
for l in lists:
for item in l:
if item in inner_list:
index= l.index(item)
l[index] = i
for i,inner_list in enumerate(groups):
for lists in A:
replace_items(i, inner_list, *lists)
print(A)
If you convert your groups into a dictionary, it will be easy to process the 3 level list using a list comprehension:
groupDict = { v:i for i,g in enumerate(groups) for v in g }
A = [ [ [ groupDict[z] for z in yz ] for yz in xyz] for xyz in A ]

Create a list with lists of subsets of a given size of set

I need to write a code that gives back the subsets of a given size of a set in a list.
So first let's say I want subsets of size 3 from a set (0,1,2,3,4,5,6,7,8)
And I want to write out the subsets in a list:
[[0,1,2],[0,2,3],[0,3,4]....]
And then I would like to go with recursion in it and compare all the elements except the first with my dictionary(graph), to check there are in my value, which is a list. The key of dictionary is the first element in my subset.
Like for example:
in [0,1,2]:
is 1 and 2 in graph[0]?
the dictionary graph is sth like: {0:[1,2,3,6,7], 1:[0,2,4,6,7]....}
And if I am done and everything is there, I want to check the next subset.
So my problem how can i put this in a list? I know I have a problem with k too but not sure how to change it.
def indep(graph,a,b):
l=list( itertools.combinations(range(a), b))
for k in l:
k=list(k)
while j<=len(k):
for j in range(len(k)):
if k[j] in graph[k[j]]:
j+=1
else:
return "no"
This will give you expected result
from itertools import combinations
original_set = (0,1,2,3,4,5,6,7,8)
final_set = [list(pair) for pair in combinations(l, 3)]
Out[6]:
[[0, 1, 2],
[0, 1, 3],
[0, 1, 4],
[0, 1, 5],
[0, 1, 6],
[0, 1, 7],
[0, 1, 8],
[0, 2, 3],
[0, 2, 4],
[0, 2, 5],
[0, 2, 6],
[0, 2, 7],
[0, 2, 8],
[0, 3, 4],
[0, 3, 5],
[0, 3, 6],
[0, 3, 7],
[0, 3, 8],
[0, 4, 5],
[0, 4, 6],
[0, 4, 7],
[0, 4, 8],
[0, 5, 6],
[0, 5, 7],
[0, 5, 8],
[0, 6, 7],
[0, 6, 8],
[0, 7, 8],
[1, 2, 3],
[1, 2, 4],
[1, 2, 5],
[1, 2, 6],
[1, 2, 7],
[1, 2, 8],
[1, 3, 4],
[1, 3, 5],
[1, 3, 6],
[1, 3, 7],
[1, 3, 8],
[1, 4, 5],
[1, 4, 6],
[1, 4, 7],
[1, 4, 8],
[1, 5, 6],
[1, 5, 7],
[1, 5, 8],
[1, 6, 7],
[1, 6, 8],
[1, 7, 8],
[2, 3, 4],
[2, 3, 5],
[2, 3, 6],
[2, 3, 7],
[2, 3, 8],
[2, 4, 5],
[2, 4, 6],
[2, 4, 7],
[2, 4, 8],
[2, 5, 6],
[2, 5, 7],
[2, 5, 8],
[2, 6, 7],
[2, 6, 8],
[2, 7, 8],
[3, 4, 5],
[3, 4, 6],
[3, 4, 7],
[3, 4, 8],
[3, 5, 6],
[3, 5, 7],
[3, 5, 8],
[3, 6, 7],
[3, 6, 8],
[3, 7, 8],
[4, 5, 6],
[4, 5, 7],
[4, 5, 8],
[4, 6, 7],
[4, 6, 8],
[4, 7, 8],
[5, 6, 7],
[5, 6, 8],
[5, 7, 8],
[6, 7, 8]]
import itertools
a = [0,1,2,3,4,5,6]
# all sets here.
sets = [list(x) for x in itertools.permutations(a, 3) if x[1]==x[2]-1]
#here are all the sets
#[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 6], [1, 2, 3], [1, 3, 4], [1, 4, 5], [1, 5, 6], [2, 0, 1], [2, 3, 4],
#[2, 4, 5], [2, 5, 6], [3, 0, 1], [3, 1, 2], [3, 4, 5], [3, 5, 6], [4, 0, 1], [4, 1, 2], [4, 2, 3], [4, 5, 6], [5, 0, 1],
#[5, 1, 2], [5, 2, 3], [5, 3, 4], [6, 0, 1], [6, 1, 2], [6, 2, 3], [6, 3, 4], [6, 4, 5]]
d = dict()
#make your thingy
for i in sets:
try:
d[i[0]] = d[i[0]]+i[1:]
except:
d[i[0]] = i[1:]
d[i[0]] = list(set(d[i[0]]))
#output D
{0: [1, 2, 3, 4, 5, 6],
1: [2, 3, 4, 5, 6],
2: [0, 1, 3, 4, 5, 6],
3: [0, 1, 2, 4, 5, 6],
4: [0, 1, 2, 3, 5, 6],
5: [0, 1, 2, 3, 4],
6: [0, 1, 2, 3, 4, 5]}
is this what you wanted? :D

comparison of two numpy arrays

I've two numpy 2d arrays (say A & B, sometime size equal or sometime not equal). I need to compare first column of both arrays and find the index of elements that occur in both arrays.
The below shown code gave me solution whenever the both arrays have different size and all elements of A are not present in B.
C=np.squeeze(A[np.array(np.where(np.in1d(A[:,0],B[:,1]))).T],axis=None)
But it is incorrect whenever all elements of A are present in B.
Can anyone suggest a solution ?
If A and B are the following:
A=np.random.randint(0,5,(10,8))
B=np.random.randint(3,7,(10,8))
>>> A
array([[4, 4, 2, 1, 4, 3, 1, 2],
[1, 1, 1, 2, 0, 3, 0, 4],
[4, 3, 1, 1, 2, 1, 1, 3],
[3, 4, 3, 0, 3, 4, 2, 0],
[4, 1, 3, 0, 1, 4, 1, 2],
[1, 1, 1, 2, 2, 2, 0, 2],
[4, 3, 4, 2, 3, 2, 3, 2],
[4, 1, 4, 0, 3, 1, 2, 3],
[3, 2, 3, 2, 4, 4, 4, 2],
[0, 1, 4, 0, 2, 2, 1, 4]])
>>> B
array([[4, 3, 5, 6, 4, 6, 3, 5],
[6, 3, 4, 4, 4, 6, 5, 4],
[5, 4, 5, 5, 5, 6, 3, 3],
[3, 5, 6, 5, 5, 5, 3, 6],
[5, 6, 5, 3, 5, 5, 5, 3],
[3, 3, 5, 3, 5, 6, 6, 3],
[6, 6, 6, 4, 6, 3, 4, 6],
[4, 4, 3, 5, 6, 6, 3, 3],
[5, 3, 4, 5, 3, 5, 5, 6],
[4, 3, 3, 6, 6, 4, 3, 4]])
You could use intersect1d to find the values that are in both
np.intersect1d(A,B)
array([3, 4])
And then argwhere to find the indices of the values in, for example, column 0 of A:
[np.argwhere(x==A[:,0]) for x in np.intersect1d(A,B)]
returns
[array([[3],
[8]]), array([[0],
[2],
[4],
[6],
[7]])]
import numpy as np
A=np.array([[4, 4, 2, 1, 4, 3, 1, 2],
[1, 1, 1, 2, 0, 3, 0],
[4, 3, 1, 1, 2, 1, 1],
[3, 4, 3, 0, 3, 4, 2],
[4, 1, 3, 0, 1, 4, 1],
[1, 1, 1, 2, 2, 2, 0],
[4, 3, 4, 2, 3, 2, 3],
[4, 1, 4, 0, 3, 1, 2],
[3, 2, 3, 2, 4, 4, 4],
[0, 1, 4, 0, 2, 2, 1]])
B=np.array([[4, 3, 5, 6, 4, 6, 3, 5],
[6, 3, 4, 4, 4, 6, 5, 4],
[5, 4, 5, 5, 5, 6, 3, 3],
[3, 5, 6, 5, 5, 5, 3, 6],
[5, 6, 5, 3, 5, 5, 5, 3],
[3, 3, 5, 3, 5, 6, 6, 3],
[6, 6, 6, 4, 6, 3, 4, 6],
[4, 4, 3, 5, 6, 6, 3, 3],
[5, 3, 4, 5, 3, 5, 5, 6],
[4, 3, 3, 6, 6, 4, 3, 4]])
matched = A.T[0][A.T[0] == B.T[0]]
>> [4,3,4]

Categories

Resources