Angular
Angular

Reputation: 623

list comprehension vs iterable. Python newbie

Say I have an array:

array=[1,0,2,3,4,0,0,5,6,0]

I want a list that returns just the numbers and not zeros. So I did this and it works:

print(list(y for y in array if y!=0)

I tried another way without list comprehension and it won't work, can someone explain why?

for y in array:
    if y!=0:
        print(list(y))

What would be another way to print a list of just the numbers without the 0's?

Edit: I tried to solve this problem using a for loop, and it works if I make an empty list on top. It works, but I don't understand why! But why does this work and other one doesn't? What's more efficient, this or the list comprehension in terms of speed/memory?

array=[1,0,2,3,4,0,0,5,6,0]
list=[]
for y in array:
    if y!=0:
        list.append(y)
print(list)

Upvotes: 3

Views: 803

Answers (5)

Sal Marquez
Sal Marquez

Reputation: 13

list() is a constructor that takes in zero parameters or an iterable, such as a list, str, or tuple. The problem is that an int is not an iterable, where as a list comprehension ([y for y in array if y!= 0]) returns an iterable and can be used to create a list Python documentation.

Upvotes: 0

Rick
Rick

Reputation: 45231

When you create a for loop, everything in that loop - EVERYTHING - executes once for each time through the loop. So this line:

print(list(y)) 

...prints a new list each trip through the loop. Whereas in the first version:

print(list(y for y in array if y!=0)) 

...there is only ONE thing printed: the results of the list() comprehension.

EDIT: If you want to fix the 'int' object is not iterable error in the second version, you can do it this way:

for y in array:
    if y!=0:
        print([y])

The list function requires an iterable object as input. An integer is not iterable, so we surround it with brackets to put it inside a list instead, which essentially does the same thing. Use the version above and you'll see that a new list is created each time through the loop.

Upvotes: 1

user3917838
user3917838

Reputation:

Lets take a good look at what you thought was right:

for y in array:
    if y!=0:
        print(list(y))

So we go through every value in the array. If the value isn't zero, we print list(y). The problem starts here. Because y is a integer, list(y) returns an error, because you can't convert an integer into a list. It would work if you did print(y).

But then comes another problem. If we print every element of the list which isn't a zero, we get something like this, because that code would only print in order:

1
2
3
4
5
6

You state in your question that you wanted a list. So this code wouldn't work either, because there would be no stored list. So we finally arrive to the right answer:

array=[1,0,2,3,4,0,0,5,6,0]
list=[]
for y in array:
    if y!=0:
        list.append(y)
print(list)

This answer stores each y value which isn't zero in a list, then finally prints out the list.

EDIT:

This is how the list comprehension works:

First of all, I can't help but observe that you have made a syntax error. :P You forgot an ending parantheses! Here's the correct code: print(list(y for y in array if y != 0)).

Second of all, I need to state that that is NOT A LIST COMPREHENSION. That is a generator. There is a tiny difference.

A list comprehension generates the list on the spot. A list comprehension looks like this: [y for y in array if y != 0]

A generator, which is what you used above, is an expression is stored. It looks like this: y for y in array if y != 0.

So instead of using list(y for y in array if y != 0, you can directly go to [y for y in array if y != 0].

So now I will explain how the "list comprehension" (generator expression) actually works. It starts out by looping through each value of array. It checks if the value is not a zero. If it isn't, it adds y to the output list. So basically, the generator expression is the same as the second working code with the for loop, except python creates the output list for you, adding some convenience.

Upvotes: 3

El'endia Starman
El'endia Starman

Reputation: 2244

With your second attempt, you had list(y) where you should've had y. As y is a single int and not an iterable, list(y) fails. This is the output:

>>> array=[1,0,2,3,4,0,0,5,6,0]
>>> print(list(y for y in array if y!=0))
[1, 2, 3, 4, 5, 6]
>>> for y in array:
    if y!=0:
        print(list(y))


Traceback (most recent call last):
  File "<pyshell#49>", line 3, in <module>
    print(list(y))
TypeError: 'int' object is not iterable
>>> for y in array:
    if y!=0:
        print(y)


1
2
3
4
5
6

Another way is to use filter, like so:

>>> print(list(filter(bool,array)))
[1, 2, 3, 4, 5, 6]

filter takes a function and iterable, applies the function to each item in the iterable, and returns only the ones where the function returned a truthy value. As bool is False if y is 0 (falsy) and True otherwise, it works perfectly for these purposes. Still, it may be useful to you to see that you can also do it this way:

>>> print(list(filter(lambda x:x != 0, array)))
[1, 2, 3, 4, 5, 6]

I see you were also wondering why the first version worked.

>>> print(list(y for y in array if y!=0))

Here, for y in array is a generator, a special kind of Python object that spits out one value every time you ask it for one, so to speak. So let me break it down this way:

print(                              )    #Print
      list(                        )     #Convert iterable to list
             for y in array              #For each y in array...
                            if y!=0      #If y is not zero...
           y                             #Include y in the iterable for list()

Does that help?

Upvotes: 1

saulspatz
saulspatz

Reputation: 5261

If you want to do it with a for loop you need to do something like this:

nonzero = []
for y in array:
   if y != 0:
      nonzero.append(y)
print(nonzero)

but a list comprehension or a filter will be better, both in terms of readability and in terms of speed.

Upvotes: 1

Related Questions