1

Say I have a 3D list in Python, but it's severely jagged:

old_list = [[[0, 1, 2], 
             [3, 4, 5, 6], 
             [7, 8]], 
            [[9, 10], 
             [11, 12, 13, 14, 15], 
             [16, 17, 18], 
             [19, 20, 21, 22]], 
            [[23, 24, 25], 
             [26, 27]]]

I need to "regularize" it so that it still has the same elements, but with 0 being used to fill in any gaps in the jagged parts. I'm aiming for something like this, which is 3x4x5:

new_list = [[[0, 1, 2, 0, 0], 
             [3, 4, 5, 6, 0], 
             [7, 8, 0, 0, 0], 
             [0, 0, 0, 0, 0]], 
            [[9, 10, 0, 0, 0], 
             [11, 12, 13, 14, 15], 
             [16, 17, 18, 0, 0], 
             [19, 20, 21, 22, 0]], 
            [[23, 24, 25, 0, 0], 
             [26, 27, 0, 0, 0], 
             [0, 0, 0, 0, 0], 
             [0, 0, 0, 0, 0]]]

Is there an efficient algorithm to do this for any number of dimensions? And better yet, without importing anything?

UPDATE 1:

The answers I've been getting are pretty okay, but not good enough for my purpose. I'm sorry. But I just found a way to solve my problem! I need to do a little more coding, though. Thanks for the answers!

UPDATE 2:

BINGO! No need to answer anymore - I got this.

  • It is already answered here https://stackoverflow.com/questions/40569220/efficiently-convert-uneven-list-of-lists-to-minimal-containing-array-padded-with – eroot163pi Aug 06 '21 at 21:42
  • Does this answer your question? [efficiently convert uneven list of lists to minimal containing array padded with nan](https://stackoverflow.com/questions/40569220/efficiently-convert-uneven-list-of-lists-to-minimal-containing-array-padded-with) – eroot163pi Aug 06 '21 at 21:43
  • Does this answer your question? [Convert Python sequence to NumPy array, filling missing values](https://stackoverflow.com/questions/38619143/convert-python-sequence-to-numpy-array-filling-missing-values) – Woodford Aug 06 '21 at 21:46
  • 1
    Those linked duplicates are all for Numpy; while Numpy might be useful for OP's overall problem, it appears the goal is to do this with built-in lists. – Karl Knechtel Aug 06 '21 at 22:04
  • 2
    OP: what happened when you tried to write code to solve the problem? You are expected to make an attempt here. – Karl Knechtel Aug 06 '21 at 22:04
  • @KarlKnechtel It would throw an error every time having to do with `int` and `list` types being used in each other's places. –  Aug 07 '21 at 12:26

3 Answers3

2

This function should do the trick:

def regularize3D(list3d, padding=0):
    # figure out how long each 1d list needs to be
    target_length = max(max(len(list1d) for list1d in list2d) for list2d in list3d)
    # now remake each sublist with the right length
    return [[list1d + [padding] * (target_length-len(list1d)) for list1d in list2d] for list2d in list3d]

# Usage example
old_list = [[[0, 1, 2],
             [3, 4, 5, 6],
             [7, 8]],
            [[9, 10],
             [11, 12, 13, 14, 15],
             [16, 17, 18],
             [19, 20, 21, 22]],
            [[23, 24, 25],
             [26, 27]]]
new_list = regularize3D(old_list)
print(new_list)

# lists are mutable
# visual "unit test" ensure modifying old list does not modify new list
old_list[0][0][0] = 90000
print(new_list) # 90000 not visible at (0,0,0), test passed
DivideByZero
  • 423
  • 6
  • 14
1

Here is a function I made that will turn any 2D array in the 3D array into the smallest n by n array that fills in the missing spots with 0s:

def reform(old_list):
  for twoD in old_list:
    length = len(twoD)
    maxWidth = 0
    for oneD in twoD:
      if maxWidth < len(oneD):
        maxWidth = len(oneD)
    dimensions = max(maxWidth,length)
    for oneD in twoD:
      while dimensions != len(oneD):
        oneD.append(0)
    while len(twoD) != dimensions:
      newRow = []
      for i in range(dimensions):
        newRow.append(0)
      twoD.append(newRow)
  return old_list

Then, we can print out the results by doing:

for twoD in new_list:
  for oneD in twoD:
    print(oneD)
  print()

If our old_list is defined as:

old_list = [[[0, 1, 2], 
             [3, 4, 5, 6], 
             [7, 8]], 
            [[9, 10], 
             [11, 12, 13, 14, 15], 
             [16, 17, 18], 
             [19, 20, 21, 22]], 
            [[23, 24, 25], 
             [26, 27]]]

The following output will be:

[0, 1, 2, 0]
[3, 4, 5, 6]
[7, 8, 0, 0]
[0, 0, 0, 0]

[9, 10, 0, 0, 0]
[11, 12, 13, 14, 15]
[16, 17, 18, 0, 0]
[19, 20, 21, 22, 0]
[0, 0, 0, 0, 0]

[23, 24, 25]
[26, 27, 0]
[0, 0, 0]
Aniketh Malyala
  • 2,650
  • 1
  • 5
  • 14
1

It seems to me that answers to close questions are mostly about 2D arrays, if not please comment. Some of them are much more complete in terms of measuring efficiency than the one provided here, but still its probably efficient (note that max_size_z and max_size_y could be done in one for loop if we sucrificed some "pythonicalization")

max_size_z = max([len(item) for sublist in old_list for item in sublist])
max_size_y = max([len(sublist) for sublist in old_list ])
new_array = np.zeros ((len(old_list),max_size_y,max_size_z),dtype=int) # efficient mem allocation "should" make this fast
for new_sublist,old_sublist in zip(new_array,old_list):
    for new_item,old_item in zip(new_sublist,old_sublist):
        new_item[:len(old_item)] = old_item
ntg
  • 12,950
  • 7
  • 74
  • 95
  • I want this to work with any dimensions. Maybe have a function with recursion? –  Aug 10 '21 at 14:27