0

I have a list of numbers as follows:

list = [5,6,4,7,8]

I need to build a 2d NumPy array using the list above applying the following logic:

arr = np.array([[k1+k2, -k2, 0, 0, 0],
                [-k2, k2+k3, -k3, 0, 0],
                [0, -k3, k3+k4, -k4, 0],
                [0, 0, -k4, k4+k5, -k5],
                [0, 0, 0, -k5, k5]])

k - are the elements in the list, for ex: k1=5, k2=6 and so on.

So, the expected output in this example should look like:

arr = np.array([[11, -6, 0, 0, 0],
                [-6, 10, -4, 0, 0],
                [0, -4, 11, -7, 0],
                [0, 0, -7, 15, -8],
                [0, 0, 0, -8, 8]])

Appreciate any help to build this logic.

5
  • Hint: don't use python keywords for variable names. Instead of list use lst or L my_list. This will prevent you from running in Error messages you will have trouble to resolve. Commented Sep 23, 2022 at 23:05
  • Thanks for the comment. Actually I don't use python keywords, just happened to use here. Commented Sep 23, 2022 at 23:11
  • this seems pretty straightforward and you've already written out the algorithm. can you show us what you've tried and where you're stuck? Commented Sep 23, 2022 at 23:13
  • I haven't been able to write any logic yet. I was thinking to approach using for loops to create multiple lists, then combining them into a single list, thus make a list of lists. Commented Sep 23, 2022 at 23:16
  • See my updated answer for an improved version of code for actual use. Commented Sep 25, 2022 at 0:52

2 Answers 2

2

The best came to my mind is to use several arrays built using np.diagflat() function and sum them up.

lst = [5,6,4,7,8]
res = np.diagflat(lst)
res += np.diagflat(lst[1:] + [0])
res -= np.diagflat(lst[1:], k=-1)
res -= np.diagflat(lst[1:], k=1)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Boris for your kind help.
Check out my answer for improved version of your approach requiring unnecessary creation of the entire 2D array multiple times.
0

Along with explanation of the logic behind in the other answer provided solution I would like to give here an improved version of Boris Silantevs code for actual use. The improvement reduces the amount of times a full 2D array is created from four times to one time keeping the advantage of numpy vectorization:

L = [5,6,4,7,8]
lenL = len(L)
np_L = np.array(L)
arr  = np.diagflat( np_L + np.append(np_L[1:],0) )
i_diagl = np.arange(lenL-1)
i_subdg = i_diagl + 1 
arr[i_diagl, i_subdg] = arr[i_subdg, i_diagl] = -np_L[1:] 

And here the explanation of the logic:

The first code block given below explains the logic behind the numpy vectorized solution providing the equivalent pure Python code using a loop and the second block provides comments on numpy np.diagflat() method for diagonal writing of values to a numpy array:

res = np.array([[11, -6,  0,  0,  0],
                [-6, 10, -4,  0,  0],
                [ 0, -4, 11, -7,  0],
                [ 0,  0, -7, 15, -8],
                [ 0,  0,  0, -8,  8]])
# Appreciate any help to build this logic: 
L = [5,6,4,7,8]
s_L = len(L) 
arr = np.zeros((s_L,s_L))
L += [0] # extend L to allow iterating up to s_L == len(L)
for i in range(s_L):
    arr[i, i] = L[i]+L[i+1] # <-- needs L += [0]
    if i < s_L-1:
        arr[i+1, i] = arr[i,i+1] = -L[i+1]
print (arr)
assert np.all(arr == res)

And below the numpy way of doing the same as the code above:

L = [5,6,4,7,8]
arr = np.diagflat(L) # writes along the diagonal of the array
print(arr) # gives: 
#  [[5 0 0 0 0]
#   [0 6 0 0 0]
#   [0 0 4 0 0]
#   [0 0 0 7 0]
#   [0 0 0 0 8]]
arr += np.diagflat(L[1:] + [0]) # equivalent to L+=[0] in first code block
print(arr) # gives: 
#  [[11  0  0  0  0]
#   [ 0 10  0  0  0]
#   [ 0  0 11  0  0]
#   [ 0  0  0 15  0]
#   [ 0  0  0  0  8]]
arr -= np.diagflat(L[1:], k=-1) # k=-1 writes to diagonal below the main one
print(arr) # gives: 
#  [[11  0  0  0  0]
#   [-6 10  0  0  0]
#   [ 0 -4 11  0  0]
#   [ 0  0 -7 15  0]
#   [ 0  0  0 -8  8]]
arr -= np.diagflat(L[1:], k=1) # k=1 writes to diagonal above the main one
print(arr) # gives: 
#  [[11 -6  0  0  0]
#   [-6 10 -4  0  0]
#   [ 0 -4 11 -7  0]
#   [ 0  0 -7 15 -8]
#   [ 0  0  0 -8  8]]

1 Comment

Thank you Claudio, I am going to test it rn

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.