Python – произвольно заполнять 2D-массив с заданным числом 1

Предположим, что у меня есть 2D-массив (8×8) из 0. Я хотел бы заполнить этот массив заданным числом 1, но случайным образом. Например, предположим, что я хочу разместить ровно 16 1 в сетке наугад, в результате чего что-то вроде этого:

[[0, 0, 0, 1, 0, 0, 1, 0], [1, 0, 0, 0, 0, 0, 0, 1], [0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0], [0, 1, 1, 0, 0, 0, 0, 1]] 

Результирующее размещение 1 не имеет значения ни малейшей, пока это случайное (или случайное, как позволяет Python).

Мой код технически работает, но я думаю, что это ужасно неэффективно. Все, что я делаю, это установить вероятность того, что каждое число станет равным от 1 до n/s , где n – количество желаемых 1, а s – размер сетки (то есть количество элементов), а затем я проверяю, добавлено правильное количество 1. Вот код (Python 2.7):

 length = 8 numOnes = 16 while True: board = [[(random.random() < float(numOnes)/(length**2))*1 for x in xrange(length)] for x in xrange(length)] if sum([subarr.count(1) for subarr in board]) == 16: break print board 

Хотя это работает , это похоже на метод обхода. Есть ли лучший (то есть более эффективный) способ сделать это? Я предвидел запуск этого кода много раз (сотни тысяч, если не миллионы), поэтому скорость вызывает беспокойство.

Либо перетасовать список из 16 1 и 48 0:

 board = [1]*16 + 48*[0] random.shuffle(board) board = [board[i:i+8] for i in xrange(0, 64, 8)] 

или заполнить доску 0s и выбрать случайную выборку из 16 позиций, чтобы положить 1s в:

 board = [[0]*8 for i in xrange(8)] for pos in random.sample(xrange(64), 16): board[pos//8][pos%8] = 1 

Я сделал их, сделал нули, объединил их, перетасовал и переделал.

 import numpy as np def make_board(shape, ones): o = np.ones(ones, dtype=np.int) z = np.zeros(np.product(shape) - ones, dtype=np.int) board = np.concatenate([o, z]) np.random.shuffle(board) return board.reshape(shape) make_board((8,8), 16) 

Редактировать.

Для чего это стоит, подход user2357112 с numpy быстро …

 def make_board(shape, ones): size = np.product(shape) board = np.zeros(size, dtype=np.int) i = np.random.choice(np.arange(size), ones) board[i] = 1 return board.reshape(shape)