Home > OS >  Why is the my while-loop looping indefinitely when appending to the numpy array?
Why is the my while-loop looping indefinitely when appending to the numpy array?

Time:07-15

Ask the user to input a sequence of numbers. Then calculate the mean and print the result. Here is one solution.

 user_input = input('Please enter a number type exit to stop:> ')
numbers = []
while user_input.lower() != 'exit':
    while not user_input.isdigit():
        print('That is not a number! Numbers only please:> ')
        user_input = input('Try again:> ')
    numbers.append(int(user_input))
    user_input = input('Please enter next number:> ')
total = 0
for number in numbers:
    total  = number

print(f'Mean is {total/len(numbers)}')
print(sum(numbers)/len(numbers))

Now, my goal is to attempt the question using the following logic and with slight modification to the above code.

  • collect the numbers from the user

  • store them one by one in a NumPy

  • append them one by one in a NumPy array.

  • use the np.ndarray.mean to get the mean

    modification to above solution

     import numpy as np
     user_nums = np.array([])
     user_input = input('Please enter a number type exit to stop:> ')
     while user_input.lower() != 'exit':
         while not user_input.isdigit():
             print('That is not a number! Numbers only please:> ')
             user_input = input('Try again:> ')
         np.append(user_nums,float(user_input))  # append user input to user_nums
    
     mean = user_nums.mean()
     print("mean is ",mean)
    

After inputting the first number, the program takes forever to continue running leaving me no choice but to force-close the program. Can you identify my mistakes? Thanks for your kind assistance in advance.

CodePudding user response:

Before diving into why numpy arrays don't work like python list, consider why you need numpy array for the problem and why wouldn't a python list work?

After answering the above to yourself, lets spend some time to do a deep dive and hope this answer helps others.


From https://numpy.org/devdocs/user/whatisnumpy.html

At the core of the NumPy package, is the ndarray object. This encapsulates n-dimensional arrays of homogeneous data types, with many operations being performed in compiled code for performance. There are several important differences between NumPy arrays and the standard Python sequences:

  • NumPy arrays have a fixed size at creation, unlike Python lists (which can grow dynamically). Changing the size of an ndarray will create a new array and delete the original.

Appending / Concatenating in Numpy

Python generally allows many dynamic operations meaning they can be arbitrary initialised and modified afterwards, e.g.

>>> l = [1,2,3]
>>> l.append(4)
>>> l
[1, 2, 3, 4]

On the surface, when you are trying to use np.append, it seems to work seamlessly like Python objects.

>>> x = np.array([1,2,3]) 
>>> np.append(x, [4])
array([1, 2, 3, 4])

Under the hood, it is trying to convert a the numpy array into a Python list object, append and then recast the list object into a new numpy array, see


Going back to original question in the post

Since in Numpy when array appending to array uses the Python list object, if you really need the final data structure of the list/array to be a numpy.array, why don't you try doing this:

nums = []
while user_input.lower() != 'exit':
    nums.append(float(input('Try again:> ')))

# Convert list of floats to numpy array.
nums_array = np.array(nums)
print(nums_array.mean())

De-nesting while loops

After dealing with the types, now if we look at the "nested while" loops esp. when checking conditions of the same variable, it usually mean sometime can be simplified.

Without messing with loops, you can test the conditions in Python by casting the condition into boolean objects, e.g.

>>> input_text = "abc"
>>> bool(input_text.lower())
True
>>> bool(input_text.lower() == 'exit')
False
>>> bool(input_text.isdigit())
False

If we look at the nested while loop:

while user_input.lower() != 'exit':
    while not user_input.isdigit():
        ...

It looks like it's performing checks on the same variable user_input and there's no specific need to make the checks hierarchically or in the order of the conditions. Effectively, it is checking:

  • if the user_input is "exit" then
  • if the user_input is not a digit.

When putting the conditions hierarchically, it will caused some "unexpected behavior" =)

>>> input_text = "abc"
>>> while input_text.lower() !=  "exit":
...     print('outerloop loop')
...     while not input_text.isdigit(): 
...         print('inner loop')

But if you try to check the conditions together:

# Now it doesn't loop unexpectedly.
>>> input_text = "abc"
>>> while input_text.lower() !=  "exit" and input_text.isdigit():
...     print("looping...")

And

# Now when the input is a digit, it is looping expectedly.
>>> input_text = "123"
>>> while input_text.lower() !=  "exit" and input_text.isdigit():
...     print("looping...")
looping...
looping...
looping...

But why did it work in Python list and not Numpy array?

The issue isn't about the numpy vs list but what the inputs you were testing with.

Possibly it's because you were testing with different inputs when testing the two code snippet. Regardless of the data-type that you are using to store the numbers, the nested-while loop you have in the question will result in infinite loop with non-digit string input that is not exit or EXIT.

  • Related