Home > Software engineering >  Generate 3D numpy array based on provided pattern
Generate 3D numpy array based on provided pattern

Time:04-05

Could you tell me if there is any 'smart' way to generate a 3D numpy array based on provided pattern? Let me explain what I mean by this. E.g., if pattern is [1, 4, 6, 4, 1], corresponding 2D array for it would be:

[
    [1, 1, 1, 1, 1],
    [1, 4, 4, 4, 1],
    [1, 4, 6, 4, 1],
    [1, 4, 4, 4, 1],
    [1, 1, 1, 1, 1]
]

And 3D array is similar to 2D. If you imagine that 3D array as a cube: just one 6 in the center of 'cube', twenty six 4s around it in the closest neighborhood, and the rest 1s. I apologize for potentially confusing explanation, I'm not a native English speaker. Please ask if something is unclear. Thanks!

Any python library can be used.

CodePudding user response:

You can use numpy.pad to add "layers" around your center number one by one (like an onion (well, a very cubic onion, actually) ):

pattern = [1,4,6]

x = np.array(pattern[-1]).reshape([1,1,1])
for p in reversed(pattern[:-1]):
    x = np.pad(x, mode='constant', constant_values=p, pad_width=1)
    
print(x)
#[[[1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]]
#
# [[1 1 1 1 1]
#  [1 4 4 4 1]
#  [1 4 4 4 1]
#  [1 4 4 4 1]
#  [1 1 1 1 1]]
#
# [[1 1 1 1 1]
#  [1 4 4 4 1]
#  [1 4 6 4 1]
#  [1 4 4 4 1]
#  [1 1 1 1 1]]
#
# [[1 1 1 1 1]
#  [1 4 4 4 1]
#  [1 4 4 4 1]
#  [1 4 4 4 1]
#  [1 1 1 1 1]]
#
# [[1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]
#  [1 1 1 1 1]]]

The code above should work with an arbitrary number of layers (in fact, it also works for an arbitrary amount of dimensions, if you adapt the reshape). However, it scales poorly with the number of layers, due to the for-loop. While it certainly is overkill to vectorize this for-loop in this application, I'd be open for suggestions if anyone has an idea.

CodePudding user response:

The tricky part is generating the indices matching the pattern. The following should work for palindromes:

a = np.array([1,4,6,4,1])
i = np.ceil((np.r_[:2, 2:-1:-1][:, None] * np.r_[:2, 2:-1:-1]) / 2).astype(int)
a[i]

output:

array([[1, 1, 1, 1, 1],
       [1, 4, 4, 4, 1],
       [1, 4, 6, 4, 1],
       [1, 4, 4, 4, 1],
       [1, 1, 1, 1, 1]])

CodePudding user response:

Given:

import numpy as np
a = np.array([1, 4, 6, 4, 1], int)

This seems like a nice method:

result = np.stack(np.meshgrid(a, a, a), axis=-1).min(axis=-1)

Same idea but more efficient:

from functools import reduce
result = reduce(np.minimum, np.ix_(*3*(a,)))
  • Related