Including an AND statement in a Python List Comprehension
<p>I'm trying to create a function for an array. The array will go in and if the value is 0 it will be put to the back of the list. My function works most of the time, but the only issue is that the Boolean value False keeps getting interpreted as 0. I've created an AND statement to differentiate 0 and False, but it is not working, and I can't figure out why. Can you not have AND statements in list comprehension? </p>

<pre><code>def move_zeros(array):
    [array.insert(len(array), array.pop(array.index(x))) for x in array if x == 0 and x is not False]
    return array
</code></pre>

<p>I've added two examples.One works. The other doesn't for what I'd like to accomplish. </p>

<p>Input: [1,"a", 2, 0, 3, "b"] Output: [1, "a", 2, 3, "b", 0] This works</p>

<p>Input: [1, False, 2, 0, 3, "b"] Output: [1, 2, 3, "b", False, 0] This doesn't work, because False is being moved to the end of the list when I want to pass over it.</p>

<p>A loop alternative to your list comprehension.  It still modifies the list.  As noted by others <code>x is 0</code> simplifies the distinction between <code>0</code> and <code>False</code>:</p>

<pre><code>In [106]: al=[0, 1, 2, False, True, 3,0,10]
In [107]: for i,x in enumerate(al):
     ...:     if x is 0:
     ...:         value = al.pop(i)
     ...:         al.append(value)
     ...:         
In [108]: al
Out[108]: [1, 2, False, True, 3, 10, 0, 0]
</code></pre>

<p>With side effects like this, a loop is better than a comprehension.  A comprehension should be used in the:</p>

<pre><code>return [.... for x in al if ...] 
</code></pre>

<p>sense.  You could also use enumerate in the comprehension:</p>

<pre><code>return [fun(x, i) for i, x in enumerate(al) if x...]
</code></pre>

<p>In a clear list comprehension, the list will only appear once; tests and returned values will depend only on the iteration variables, not the original list.</p>

<p>===================</p>

<p>Beware that <code>0</code> and <code>False</code> are often treated as the same.  For example operations that expect numbers treat <code>False</code> as <code>0</code>, and <code>True</code> as 1.  And functions that expect booleans will treat <code>0</code> as <code>False</code>.</p>

<pre><code>In [117]: [x+1 for x in al]
Out[117]: [1, 2, 3, 1, 2, 4, 1, 11]
In [118]: al=[0, 1, 2, False, True, 3,0,10]
In [119]: sum(al)
Out[119]: 17
</code></pre>

<p>=================</p>

<p>Example with <code>and</code> in list comprehension:</p>

<pre><code>In [137]: [x for x in al if x==0]
Out[137]: [0, False, 0]
In [138]: [x for x in al if x==0 and x is not False]
Out[138]: [0, 0]
In [140]: [x for x in al if not (x==0 and x is not False)]
Out[140]: [1, 2, False, True, 3, 10]
</code></pre>

<p>============</p>

<p>Another possible test - of the str representation:</p>

<pre><code>In [143]: [x for x in al if str(x)!='0']
Out[143]: [1, 2, False, True, 3, 10]
</code></pre>

<p>================</p>

<p>Your problem isn't with the test, but with the <code>al.index(x)</code>; it's matching both <code>0</code> and <code>False</code>, and removing the first, regardless of which <code>x</code> is passing your test.</p>

<p>Version with <code>al.index(x)</code>:</p>

<pre><code>In [396]: al=[1,False,2, 0,3,"b"]
In [397]: for x in al:
     ...:     if x ==0 and x is not False:
     ...:         al.append(al.pop(al.index(x)))
     ...:         
In [398]: al
Out[398]: [1, 2, 0, 3, 'b', False]
</code></pre>

<p>Version with enumerate <code>i</code></p>

<pre><code>In [399]: al=[1,False,2, 0,3,"b"]
In [400]: for i,x in enumerate(al):
     ...:     if x ==0 and x is not False:
     ...:         al.append(al.pop(i))
     ...:         
In [401]: al
Out[401]: [1, False, 2, 3, 'b', 0]
</code></pre>

<p>Or in your function:</p>

<pre><code>def move_zeros(array):
   [array.insert(len(array), array.pop(i)) for i,x in enumerate(array) if (x == 0 and x is not False)]
   return array

In [403]: al=[1,False,2, 0,3,"b"]
In [404]: move_zeros(al)
Out[404]: [1, False, 2, 3, 'b', 0]
</code></pre>

<p>testing the <code>index</code> in isolation:</p>

<pre><code>In [405]: al=[1,False,2, 0,3,"b"]
In [406]: al.index(0)
Out[406]: 1
In [407]: al.index(False)
Out[407]: 1
</code></pre>

python arrays list-comprehension