sample n random permutations of a list in python [duplicate] - python

This question already has answers here:
python shuffling with a parameter to get the same result
(4 answers)
Closed 1 year ago.
I have a list of values such as:
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
and I need to reproducibly return n random shuffles of this list.
Ideally, I need a function with seed such that f(lst, samples = 2, seed = 1234)
-> return two shuffles of the list lst such as:
[5, 7, 1, 6, 2, 8, 0, 4, 3, 9]
[8, 7, 3, 0, 1, 4, 5, 9, 6, 2]
Repeated execution of this function (with the same seed) would return the same two lists.

This works without numpy:
import sys
import random
some_seed = 123 # change this to get different shuffles
def n_shuffles(lst, n):
r = random.Random(some_seed)
for _ in range(n):
_l = lst[:]
r.shuffle(_l)
yield _l
l = list(range(10))
>>> [*n_shuffles(l, 3)]
[[8, 7, 5, 9, 2, 3, 6, 1, 4, 0], [7, 6, 3, 4, 1, 0, 2, 5, 9, 8], [1, 8, 5, 6, 4, 7, 9, 0, 2, 3]]
>>> [*n_shuffles(l, 3)]
[[8, 7, 5, 9, 2, 3, 6, 1, 4, 0], [7, 6, 3, 4, 1, 0, 2, 5, 9, 8], [1, 8, 5, 6, 4, 7, 9, 0, 2, 3]]

You can use np.copy
import numpy as np
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
def shuffle_list(arr:list,samples:int,seed:int):
np.random.seed(seed)
res = []
for i in range(samples):
arr_copy=np.copy(arr)
np.random.shuffle(arr_copy)
res.append(arr_copy)
return res
#test
print(shuffle_list(lst,2,1234))
output:
[array([7, 2, 9, 1, 0, 8, 4, 5, 6, 3]), array([7, 3, 5, 1, 4, 8, 0, 2, 6, 9])]

Ok, it wasn't an exact duplicate, but the proposed topic has pretty much shown that re-setting the seed() is the key:
import random
def shuffles(l,n):
random.seed(4) # just the same one as in the referred topic
return [random.sample(l,k=len(l)) for i in range(n)]
print(shuffles([1,2,3,4],3))
print("again:")
print(shuffles([1,2,3,4],3))
will generate
[[2, 4, 1, 3], [4, 1, 3, 2], [1, 2, 3, 4]]
again:
[[2, 4, 1, 3], [4, 1, 3, 2], [1, 2, 3, 4]]

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])

Python: How to split a list into ordered chunks

If I have the following list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Then
np.array_split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 3)
Returns
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]
Is there a way to get the sub-arrays in the following order?
[array([0, 3, 6, 9]), array([1, 4, 7]), array([2, 5, 8])]
As the lists are of differing lengths, a numpy.ndarray isn't possible without a bit of fiddling, as all sub-arrays must be the same length.
However, if a simple list meets your requirement, you can use:
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l2 = []
for i in range(3):
l2.append(l[i::3])
Output:
[[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]]
Or more concisely, giving the same output:
[l[i::3] for i in range(3)]
Let's look into source code refactor of np.array_split:
def array_split(arr, Nsections):
Neach_section, extras = divmod(len(arr), Nsections)
section_sizes = ([0] + extras * [Neach_section + 1] + (Nsections - extras) * [Neach_section])
div_points = np.array(section_sizes).cumsum()
sub_arrs = []
for i in range(Nsections):
st = div_points[i]
end = div_points[i + 1]
sub_arrs.append(arr[st:end])
return sub_arrs
Taking into account your example arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] and Nsections = 3 it will construct section sizes [0, 4, 3, 3] and dividing points [0, 4, 7, 10]. Then do something like this:
[arr[div_points[i]:div_points[i + 1]] for i in range(3)]
Trying to mimic behaviour of numpy, indeed,
def array_split_withswap(arr, N):
sub_arrs = []
for i in range(N):
sub_arrs.append(arr[i::N])
Is the best option to go with (like in #S3DEV solution).

Array problems in for loop

I want to go from one array A of 10 elements to the array B of 100 elements.
Each element of B from 0 to 9 is equal to the element 0 of A
Each element of B from 10 to 19 is equal to the element 1 of A
....
Each element of B from 90 to 99 is equal to the element 9 of A
I did the following code but it does not work
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A = np.asarray(a)
b = []
for i in range(len(A)*10):
b.append(0)
B = np.asarray(b)
for i in range(len(A)):
for j in range(9):
B[j]=A[i]
Expected result:
B [ 0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2
...,
9,9,9,9,9,9,9,9,9,9 ]
You are saving values only in first 9 list elements. You have to 'scale' it by adding i*10 to index.
import numpy as np
a=[0, 1, 2, 3, 4, 5, 6, 7]
A = np.asarray(a)
b = []
for i in range(len(A)**2):
b.append(0)
B = np.asarray(b)
for i in range(len(A)):
for j in range(len(A)):
B[j + i*len(A)]=A[i]
print(B)
This works for me:
>>> a = [1,2,3]
>>> [ x for i in a for x in [i]*3]
[1, 1, 1, 2, 2, 2, 3, 3, 3]
>>>
You may replace 3 with 10 or whatever you like.
Answering the question from Jacob:
>>> [[a]*10 for a in A]
[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]]
You should avoid loops with numpy whenever possible. It kind of defeats the point. Here you can just use repeat():
import numpy as np
a=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A = np.asarray(a)
B = A.repeat(10)
B:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9])
If want the a nested list, just reshape:
B = A.repeat(10).reshape(-1, 10)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
[6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
[7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]])
You can use numpy and specify how many iterations of each element you want:
import numpy as np
A = [1,2,3,4]
B = [np.full(10, a) for a in A]
print(B)
Or if you prefer to not use numpy, instead use:
A = [1,2,3,4]
B = [[a]*10 for a in A]
print(B)
Giving you the wanted list B
Try this:
a = [*range(10)]
b = []
for i in range(10):
b.extend([a[i]* 10])
B = np.asarray(b)
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = []
for x in a:
b += [x] * 10
print b
This answer is better, idea from lenik
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [x for x in a for i in range(10)]
print b
Answer in a single line: print([item for sublist in [[i]*10 for i in range(1,10)] for item in sublist])
If a were a generic list and not an ordered sequence
In [20]: a = [1, 'a', 3.14159, False, {1:2, 3:4}]
you could do as follows
In [21]: [_ for _ in (zip(*(a for _ in a))) for _ in _]
Out[21]:
[1,
1,
1,
1,
1,
'a',
'a',
'a',
'a',
'a',
3.14159,
3.14159,
3.14159,
3.14159,
3.14159,
False,
False,
False,
False,
False,
{1: 2, 3: 4},
{1: 2, 3: 4},
{1: 2, 3: 4},
{1: 2, 3: 4},
{1: 2, 3: 4}]
list1=[]
list2=[]
for i in range (0,10,1):
list1.append(i)
print(list1)
for i in range (0,10,1):
for j in range (0,10,1):
j=i
list2.append(j)
print(list2)

Fastest numpy way to remove a list of cells from a 2d array

I have a very large 2D numpy array of m x n elements. For each row, I need to remove exactly one element. So for example from a 4x6 matrix I might need to delete [0, 1], [1, 4], [2, 3], and [3, 3] - I have this set of coordinates stored in a list. In the end, the matrix will ultimately shrink in width by 1.
Is there a standard way to do this using a mask? Ideally, I need this to be as performant as possible.
Here is a method that use ravel_multi_index() to calculate one-dim index, and then delete() the elements, and reshape back to two-dim array:
import numpy as np
n = 12
a = np.repeat(np.arange(10)[None, :], n, axis=0)
index = np.random.randint(0, 10, n)
ravel_index = np.ravel_multi_index((np.arange(n), index), a.shape)
np.delete(a, ravel_index).reshape(n, -1)
the index:
array([4, 6, 9, 0, 3, 5, 3, 8, 9, 8, 4, 4])
the result:
array([[0, 1, 2, 3, 4, 5, 6, 7, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 9],
[0, 1, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 4, 5, 6, 7, 8, 9]])

Create a list of list with flexible input (Python) [duplicate]

This question already has answers here:
How can I make a for-loop pyramid more concise in Python? [duplicate]
(4 answers)
Closed 5 years ago.
I currently have a function that creates a list of lists like below using 3 nested for-loops.
[[1,1,1] , [1,1,2] , .... , [3,3,3]]
However, the problem is I can't use this function if someone wants the list of list to be something like
[[1,1,1,1,1,1,1] , ..... , [9,9,9,9,9,9,9]]
which has more numbers (from 1 - 9) and more elements (7 of 1's instead of 4).
Here's my current code:
def listofList():
temp = []
for i in range(1,4):
for j in range(1,4):
for k in range(1,4):
temp.append([i,j,k])
return temp
Can someone provide me with a better solution? I want my function listofList() to be flexible where it could receive an input for both the size of the list of list and the elements inside the list.
Try the following:
def listofList(subLen, totalLen):
final = [[item for i in range(subLen)] for item in range(1, totalLen+1)]
return final
>>> listofList(9, 9)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 4, 4], [5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9]]
>>> listofList(9, 2)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2]]
>>> listofList(2, 9)
[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]]
>>>

Categories

Resources