'Problem with python while loop going over every element in 2d array

I am having problems with while loops in python right now:

while(j < len(firstx)):
    trainingset[j][0] = firstx[j]
    trainingset[j][1] = firsty[j]
    trainingset[j][2] = 1 #top
    
    print(trainingset)
    j += 1
print("j is " + str(j))
i = 0
while(i < len(firsty)):
    trainingset[j+i][0] = twox[i]
    trainingset[j+i][1] = twoy[i]
    trainingset[j+i][2] = 0 #bottom
    i += 1

Where trainingset = [[0,0,0]]*points*2 where points is a number. Also firstx and firsty and twox and twoy are all numpy arrays.

I want the training set to have 2*points array entries which go [firstx[0], firsty[0], 1] all the way to [twox[points-1], twoy[points-1], 0].

After some debugging, I am realizing that for each iteration, **every single value **in the training set is being changed, so that when j = 0 all the training set values are replaced with firstx[0], firsty[0], and 1.

What am I doing wrong?



Solution 1:[1]

In this case, I would recommend a for loop instead of a while loop; for loops are great for when you want the index to increment and you know what the last increment value should be, which is true here.

I've had to make some assumptions about the shape of your arrays based on your code. I'm assuming that:

  1. firstx, firsty, twox, and twoy are 1D NumPy arrays with either shape (length,) or (length, 1).
  2. trainingset is a 2D NumPy array with least len(firstx) + len(firsty) rows and at least 3 columns.
  3. j starts at 0 before the while loop begins.

Given these assumptions, here's some code that gives you the output you want:

len_firstx = len(firstx)

# Replace each row with index j with the desired values
for j in range(len(firstx)):
    trainingset[j][0:3] = [firstx[j], firsty[j], 1]

# Because i starts at 0, len_firstx needs to be added to the trainingset row index
for i in range(len(firsty)):
    trainingset[i + len_firstx][0:3] = [twox[i], twoy[i], 0]

Let me know if you have any questions.

EDIT: Alright, looks like the above doesn't work correctly on rare occasions, not sure why, so if it's being fickle, you can change trainingset[j][0:3] and trainingset[i + len_firstx][0:3] to trainingset[j, 0:3] and trainingset[i + len_firstx, 0:3].

I think it has something to do with the shape of the trainingset array, but I'm not quite sure.

EDIT 2: There's also a more Pythonic way to do what you want instead of using loops. It standardizes the shapes of the four arrays assumed to be 1D (firstx, twox, etc. -- also, if you could let me know exactly what shape these arrays have, that would be super helpful and I could simplify the code!) and then makes the appropriate rows and columns in trainingset have the corresponding values.

# Function to reshape the 1D arrays.
# Works for shapes (length,), (length, 1), and (1, length).
def reshape_1d_array(arr):
    shape = arr.shape
    if len(shape) == 1:
        return arr[:, None]
    elif shape[0] >= shape[1]:
        return arr
    else:
        return arr.T

# Reshape the 1D arrays
firstx = reshape_1d_array(firstx)
firsty = reshape_1d_array(firsty)
twox = reshape_1d_array(twox)
twoy = reshape_1d_array(twoy)

len_firstx = len(firstx)

# The following 2 lines do what the loops did, but in 1 step.
arr1 = np.concatenate((firstx, firsty[0:len_firstx], np.array([[1]*len_firstx]).T), axis=1)
arr2 = np.concatenate((twox, twoy[0:len_firstx], np.array([[0]*len_firstx]).T), axis=1)

# Now put arr1 and arr2 where they're supposed to go in trainingset.
trainingset[:len_firstx, 0:3] = arr1
trainingset[len_firstx:len_firstx + len(firsty), 0:3] = arr2

This gives the same result as the two for loops I wrote before, but is faster if firstx has more than ~50 elements.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1