I'll present an example for smaller value of n:
n = 4
First create a full array with results of your function:
arr = np.fromfunction(f, (n,n), dtype='complex')
So far the result (with reduced precision) is:
array([[ 0. +0.j, -0.5 +0.5j , -0.8 +0.4j , -0.9 +0.3j ],
[ 0.5 +0.j, 0.2 +0.6j , -0.25 +0.75j , -0.53846+0.69231j],
[ 0.66667+0.j, 0.5 +0.5j , 0.15385+0.76923j, -0.16667+0.83333j],
[ 0.75 +0.j, 0.64706+0.41176j, 0.4 +0.7j , 0.12 +0.84j ]])
Then, to generate your expected result, run:
result = [ [i,j, arr[i,j]] for i, j in zip(*np.triu_indices(n)) ]
The result is a list of lists containing:
[[0, 0, 0j]],
[0, 1, (-0.5 +0.5j)]],
[0, 2, (-0.8 +0.4j)],
[0, 3, (-0.89999+0.3j)],
[1, 1, ( 0.2 +0.6j)],
[1, 2, (-0.25 +0.75j)],
[1, 3, (-0.53846+0.69231j)],
[2, 2, ( 0.15385+0.76923j)],
[2, 3, (-0.16667+0.83333j)],
[3, 3, ( 0.12 +0.84j)]]
(I also reduced the precision).
If you run into problems concerning available memory, then don't create
any temporary array, but run instead:
result = [ [i, j, f(i,j)] for i, j in zip(*np.triu_indices(n)) ]
But this variant will run significantly slower than using np.fromfunction.