Home > other >  How to initialize locations of numpy array using dictionary keys and values?
How to initialize locations of numpy array using dictionary keys and values?

Time:01-05

I have the following numpy array which is basically a 3 channel image:

arr = np.zeros((6, 4, 3), dtype=np.float32)

# dictionary of values, key is array location
values_of_channel_0 = {
        (0, 2) : 1,  
        (1, 0) : 1,  
        (1, 3) : 5,  
        (2, 1) : 2,  
        (2, 2) : 3,  
        (2, 3) : 1,  
        (3, 0) : 1,  
        (3, 2) : 2,  
        (4, 0) : 2,  
        (4, 2) : 20,  
        (5, 0) : 1,  
        (5, 2) : 10, 
        (5, 3) : 1 
}

I am trying to find the most elegant way to set all the values of the 3rd channel according to the dictionary. Here is what I tried:

locations = list(values_of_channel_0.keys())
values = list(values_of_channel_0.values())
arr[lc,0] = values # trying to set the 3rd channel

But this fails.

Is there a way in which this can be done without looping over keys and values?

CodePudding user response:

What's wrong with a simple loop? Something will have to iterate over the key/value-pairs you provide in your dictionary in any case?

import numpy as np

arr = np.zeros((6, 4, 3), dtype=np.float32)

# dictionary of values, key is array location
values_of_channel_0 = {
        (0, 2) : 1,
        (1, 0) : 1,
        (1, 3) : 5,
        (2, 1) : 2,
        (2, 2) : 3,
        (2, 3) : 1,
        (3, 0) : 1,
        (3, 2) : 2,
        (4, 0) : 2,
        (4, 2) : 20,
        (5, 0) : 1,
        (5, 2) : 10,
        (5, 3) : 1
}

for (a, b), v in values_of_channel_0.items():
    arr[a, b, 0] = v

print(arr)

Result:

[[[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 1.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 5.  0.  0.]]

 [[ 0.  0.  0.]
  [ 2.  0.  0.]
  [ 3.  0.  0.]
  [ 1.  0.  0.]]

 [[ 1.  0.  0.]
  [ 0.  0.  0.]
  [ 2.  0.  0.]
  [ 0.  0.  0.]]

 [[ 2.  0.  0.]
  [ 0.  0.  0.]
  [20.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  0.  0.]
  [ 0.  0.  0.]
  [10.  0.  0.]
  [ 1.  0.  0.]]]

If you insist on not looping for the assignment, you can construct a data structure that can be assigned at once:

channel_0 = [[values_of_channel_0[b, a] if (b, a) in values_of_channel_0 else 0 for a in range(4)] for b in range(6)]

arr[..., 0] = channel_0

But this is clearly rather pointless and not even more efficient. If you have some control over how values_of_channel_0 is constructed, you could consider constructing it as a nested list or array of the right dimensions immediately, to allow for this type of assignment.

Users @mechanicpig and @michaelszczesny offer a very clean alternative (which will be more efficient since it relies on the efficient implementation of zip()):

arr[(*zip(*values_of_channel_0), 0)] = list(values_of_channel_0.values())
  • Related