Search code examples
pythonarraysfor-loopnumpyany

multiple for statements in any() python


So, I have four lists. Two hold x coordinates (foodX and newPosXArray) and the other two hold y coordinates (foodX and newPosYArray). Both the food and the newPos arrays are of different dimensions because I have multiple "food sources", and multiple objects searching for the food. I want to write an if statement that does something when the objects get to within a certain distance of the food. My attempt with any()

if any(np.sqrt((newPosXArray[u]-foodX[t])**2 + (newPosYArray[u]-foodY[t])**2) <= 0.2 for t in zip(food[0], food[1]) for u in zip(newPosXArray, newPosYArray)):
#dosomething

I am getting an error TypeError: list indices must be integers, not tuple

Edit: maybe I am misunderstanding zip(). I was assuming that it condenses this

 if any(np.sqrt((newPosXArray[u]-foodX[t])**2 + (newPosYArray[u]-foodY[t])**2) <= 0.2 for t in foodX for t in foodY for u in newPosXArray for u in newPosYArray):

Typical Values of what I am working with

foodX = [5,5,-5,-5]
foodY = [5,-5,5,-5]

In [65]: newPosXArray
Out[65]:
[-0.012880860643600167,
 -0.566815786730638,
 0.7905336304903405,
 0.09006991095474826,
 0.26518652615441063,
 0.3161232055076695,
 0.681255361368023,
 -0.6849985596071202,
 0.7140832628874829,
 0.4958515031060564]


In [66]: newPosYArray
Out[66]: 
[-0.41112817779983235,
 -0.08554837651693648,
 0.8743935617169996,
 -0.9384733737088207,
 0.02423386678116546,
 -0.3735855691077572,
 -0.5251118585489394,
 0.3950871276165102,
 0.9892320167752822,
 -0.7342372054958279]

of course, none of these values will return true in the if statement because none are within a 0.2 radius of any of the food coordinates


Solution

  • Just to be clear nested loops and zip do not do the same thing:

    >>> [(i, j) for i in range(3) for j in range(3)]
    [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
    

    Whereas:

    >>> list(zip(range(3), range(3)))
    [(0, 0), (1, 1), (2, 2)]
    

    itertools.product does the same as next for loops:

    >>> import itertools
    >>> list(itertools.product(range(3), range(3)))
    [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
    

    You don't index into the array when you iterate over an array, e.g:

    >>> food = [1,2,3,4]
    >>> [f+1 for f in food]     # Note you did [food[f] for f in food]
    [2,3,4,5]
    

    So fixing your second example looks like:

    if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2 
           for t_x in foodX for t_y in foodY for u_x in newPosXArray for u_y in newPosYArray):
    

    But this iterates foodY for every foodX so assume you do want these to be zipped which would be written:

    if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2 
           for t_x, t_y in zip(foodX, foodY) for u_x, u_y in zip(newPosXArray, newPosYArray)):
    

    Or using itertools.product (which personally I don't find any easier to follow in this instance:

    import itertools
    if any(np.sqrt((u_x-t_x)**2 + (u_y-t_y)**2) <= 0.2
           for (t_x, t_y), (u_x, u_y) in itertools.product(zip(foodX, foodY), zip(newPosXArray, newPosYArray))):