3

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)
Angular
  • 603
  • 2
  • 9
  • 24
  • Can you explain why it is you believe the second version is the same as the first? – Rick Nov 30 '15 at 02:16
  • 1
    `filter(lambda el: el != 0, array)` (but ew, just use `[el for el in array if el != 0]` – Adam Smith Nov 30 '15 at 02:16
  • @RickTeachey Uh. Well in the first version I saw 'for y in array', so that's how I started the 2nd version. Then back to the first version, I saw ' if y!=0' so i wrote that in the second version. And then both of them printed out y! I do notice that in the first version, everything in converted into a list whereas the 2nd version, I attempt to only convert y into a list. But I still don't understand what's going on – Angular Nov 30 '15 at 02:20
  • temp = (y for y in array if y!=0) is type generator. list(temp) will return a list. but list(0) will give error, see here http://stackoverflow.com/questions/19523563/python-typeerror-int-object-is-not-iterable. – BAE Nov 30 '15 at 02:21
  • @RickTeachey In the 2nd version: If i just print(y), I get an iterable of all the numbers without the zeros, which is good. I just tried converting that to a list by doing list(y), but it doesn't work. – Angular Nov 30 '15 at 02:21
  • @Angular Thing is, you aren't converting "that" to a list. You are creating a new list (with one item in it) each time through the loop (as you probably understand now). – Rick Nov 30 '15 at 02:35
  • @Angular see my edited answer for a fix to second version to get rid of the error – Rick Nov 30 '15 at 03:00

5 Answers5

3

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.

  • Wow Now I get it! thanks a lot! Can you also explain how the first verion works step-by-step ( the list comprehension) – Angular Nov 30 '15 at 02:27
1

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.

Rick
  • 43,029
  • 15
  • 76
  • 119
  • I tried this, but the output I got was something like this : [[1], [2], [3], [4], [5], [6]] So it put each number into it's own list=( – Angular Nov 30 '15 at 03:52
  • That what it is supposed to do. Read my answer again: the line `print([y])` is run *every trip through the loop*. So you will get a new list, with one number in it (e.g., `[1]`, `[2]`, etc.), each time. – Rick Nov 30 '15 at 03:55
  • True. Since we're on this topic, If i do something like [0]*4, I get [0,0,0,0]. what would I do to get [0],[0],[0],[0]. – Angular Nov 30 '15 at 04:01
  • @Angular What do you intend "[0],[0],[0],[0]" to represent? Do you mean a list of lists? If so, you can just do this: `[[0] for x in range(4)]`. – Rick Nov 30 '15 at 04:14
1

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?

El'endia Starman
  • 2,204
  • 21
  • 35
  • Oh, so y is a single int becuase the for loop goes through each single number in the array? So when I do list(y), it doesn't work because it's bascially doing list( a single number) which isn't suppose to work? – Angular Nov 30 '15 at 02:25
  • print (filter(lambda x:x != 0, array)) should be OK. – BAE Nov 30 '15 at 02:29
  • @ChengchengPei: Nope, it'll print something like ``. – El'endia Starman Nov 30 '15 at 02:34
  • @Angular: See my edit for explanation of the list comprehension version. – El'endia Starman Nov 30 '15 at 02:35
  • @ChengchengPei: Python 3.3 here. – El'endia Starman Nov 30 '15 at 02:48
  • @El'endiaStarman yeah I understand it now. I never wrote everything all in 1 line before so it was hard to understand haha, I usually use for loops since I'm starting out. But I realized that the list comprehension converts the iterable to a list, facinating. It wouild take an extra step if I were to do it the for loop way, since I would have to create an empty list and then append later. – Angular Nov 30 '15 at 03:51
1

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.

saulspatz
  • 5,011
  • 5
  • 36
  • 47
0

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.