-1

I am have a numpy array:

   [[4907., 4907., 4907., ..., 4907., 4907., 4907.],
   [4907., 4907., 4907., ..., 4907., 4907., 4907.],
   [4907., 4907., 4907., ..., 4907., 4907., 4907.]]

I wish to add a specific number of leading zeros to every element of this array so that the array looks like this:

  [[0004907., 0004907., 0004907., ..., 0004907., 0004907., 0004907.],
   [0004907., 0004907., 0004907., ..., 0004907., 0004907., 0004907.],
   [0004907., 0004907., 0004907., ..., 0004907., 0004907., 0004907.]]

What is the most efficient and fast way of doing this?

  • 2
    Why do you want to do that? In general numbers do not have leading zeros – Dani Mesejo Apr 01 '20 at 16:30
  • That is not possible. Leading zeros are not allowed in numeric literals. Even if they were (and they were - in Python 2.7), they would mean that the number is written in the octal notation. – DYZ Apr 01 '20 at 16:30
  • You cannot have a float with leading zeros. Basically because it'd be completely useless – yatu Apr 01 '20 at 16:32
  • @yatu Leading zeros have nothing to do with memory. – DYZ Apr 01 '20 at 16:32
  • Hmm yes *corrected*. My point being was that in the case of `floats`, a zero on the lhs would be completely meaningless @DYZ – yatu Apr 01 '20 at 16:33
  • https://stackoverflow.com/q/134934/901925 - display python number with leading zeros. – hpaulj Apr 01 '20 at 20:12

3 Answers3

1

It's impossible to do this. The Python interpreter automatically converts numbers like 0004 to 4.

The only way to do this is by converting everything to a string. If you want to do maths with the content of your array you convert it back to float.

arr = [
    [4907., 4907., 4907.],
    [4907., 4907., 4907.],
    [4907., 4907., 4907.]
]

new_arr = []

for i in range(0, len(arr)):
    new_arr.append([])
    for j in range(0, len(arr)):
        nr = arr[i][j]
        new_arr[i].append(str(nr).zfill(len(str(nr)) + 3))


print(new_arr)


Output:

[['0004907.0', '0004907.0', '0004907.0'], ['0004907.0', '0004907.0', '0004907.0'], ['0004907.0', '0004907.0', '0004907.0']]

Edit: However, if you have to use this array a lot, the most elegant way to achieve this is to make a class in my opinion. That would feel more natural and you won't have to convert between strings and float each time. Thus being faster as well.

#Special class
class SpecialArray:
    #Your array
    arr = [
        [4907., 4907., 4907.],
        [4907., 4907., 4907.],
        [4907., 4907., 4907.]
    ]


    #Append leading zero's when class is initiated
    def __init__(self):
        temp_arr = []

        for i in range(0, len(self.arr)):
            temp_arr.append([])
            for j in range(0, len(self.arr)):
                nr = self.arr[i][j]
                temp_arr[i].append(str(nr).zfill(len(str(nr)) + 3))

        self.arr = temp_arr

    #Print out array
    def print(self):
        print(self.arr)

    #Get a value to to math
    #If asString is true, you get back the string with leading zero's (not for math)
    def get(self, x, y, asString = False):
        if not asString:
            return float(self.arr[x][y])
        else:
            return self.arr[x][y]

    #TODO: Make function to append etc here

###Rest of your program
def main():
    #Initiate your array
    arr = SpecialArray()

    #Print out whole array
    arr.print()
    #Output:
    #[['0004907.0', '0004907.0', '0004907.0'], ['0004907.0', '0004907.0', '0004907.0'], ['0004907.0', '0004907.0', '0004907.0']]


    #Print out one element
    print(arr.get(1, 2, True))
    #Output:
    #0004907.0

    #Get one element and increase by one (do math)
    x = arr.get(1,2) + 1
    print(x)
    #Output:
    #4908.0

main()


O'Niel
  • 1,622
  • 1
  • 17
  • 35
0

With one of the Python string formatting methods, we can create a simple function that pads a number to 7 places:

Display number with leading zeros

def foo(num):
    return "{:07d}".format(num)
In [301]: arr = [[4907, 12],[1, 4907]]                                                         

and use frompyfunc to apply that to all the elements of an array:

In [302]: np.frompyfunc(foo,1,1)(arr)                                                          
Out[302]: 
array([['0004907', '0000012'],
       ['0000001', '0004907']], dtype=object)

===

You don't need frompyfunc if you are just writing this to a csv. Just specify the desired fmt:

In [359]: np.savetxt('padded.txt', arr, fmt="%07d")                                            
In [360]: cat padded.txt                                                                       
0004907 0000012
0000001 0004907
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • I want to store the resulting array into a txt file. np.savetxt gives the following error:TypeError: Mismatch between array dtype ('object') and format specifier ('%.18e %.18e %.18e ... – Sabito stands with Ukraine Apr 02 '20 at 06:51
  • 1
    Why didn't you mention `np.savetxt` initially? Have you read the `savetxt` docs? Read about the `fmt` parameter? The default `fmt` is '%.18e', which obviously isn't going to work with the formatted strings. Only `%s` works with those. But you can specify the `%07d` format and save the integers. See my edit. – hpaulj Apr 02 '20 at 06:55
0

I'd recommend flattening your array to 1-dimension, applying the zfill() iteratively to each element in your newly-flattened list. This looks like

# Initiate list
l = np.array([[1,1],[2,2],[3,3],[4,4]])

print(l)

# Specify length of output string you want
desired_pad = 2

# Create a numpy array version, flatten to 1-d
flat_l = np.array(l).flatten()

# Apply zfill to each element in flattened array, then reshape to initial shape
output = np.array([str(flat_l[i]).zfill(desired_pad) for i in np.arange(0,len(flat_l))]).reshape(l.shape)

print(output)

Output

[[1 1]
 [2 2]
 [3 3]
 [4 4]]
[['01' '01']
 ['02' '02']
 ['03' '03']
 ['04' '04']]
PJ Gibson
  • 31
  • 4