Since you are using NumPy and if you are okay with an alternate vectorized solution, here's one with masking and choosing those places with np.random.choice -
def random_off_diag_fill(N, num_rand = 12, fillval=1): # Initialize array x= np.zeros((N,N),dtype=type(fillval)) # Generate flat nondiagonal indices using masking idx = np.flatnonzero(~np.eye(N,dtype=bool)) # Select num_rand random indices from those and set those # in a flattened view of the array to be as fillval x.ravel()[np.random.choice(idx, num_rand, replace=0)] = fillval return x
Sample runs -
In [57]: random_off_diag_fill(N=8, num_rand=12, fillval=1) Out[57]: array([[0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0, 0, 0]]) In [63]: random_off_diag_fill(N=5, num_rand=12, fillval=2.45) Out[63]: array([[ 0. , 0. , 0. , 0. , 2.45], [ 2.45, 0. , 2.45, 0. , 2.45], [ 0. , 2.45, 0. , 2.45, 2.45], [ 2.45, 2.45, 0. , 0. , 0. ], [ 2.45, 2.45, 0. , 2.45, 0. ]])