Posts: 8,089
Threads: 154
Joined: Sep 2016
Today I saw a post in Facebook showing visualisation from https://panjee.com on separating odd and even numbers from a list. The code goes like this:
numbers = [12, 37, 5, 42, 8, 3]
even = []
odd = []
while len(numbers) > 0:
number = numbers.pop()
if (number%2 == 0):
even.append(number)
else:
odd.append(number) It's really annoying to see non pythonic code propagated by tutoring site. I went to the site just to discover their introductiory video comparing python with other languages that has more of the same ( https://youtu.be/r9m__27-R6M?t=40s). I mean the a is 5 and a is True ...
I write all this as a word of caution with regards to such resourses...
Posts: 7,162
Threads: 122
Joined: Sep 2016
There is a lot stuff like this,and even worse when it comes to OOP tutorial for Python here has like over 70% of theme a lot of wrong stuff in them.
As mention in post,also MIT has a lot of wrong stuff in there teaching.
Posts: 3,458
Threads: 101
Joined: Sep 2016
Aside from just using while numbers , or just using a for loop, what else isn't pythonic about it?
I a little bit don't like if/else used like this, because it isn't obvious at a glance that there's *always* something that happens, every single iteration, so I'd write it like this:
>>> numbers = [12, 37, 5, 42, 8, 3]
>>> separated = {'odd': [], 'even': [] }
>>> for num in numbers:
... key = 'even' if num % 2 == 0 else 'odd'
... separated[key].append(num)
...
>>> separated
{'odd': [37, 5, 3], 'even': [12, 42, 8]} But I don't know if that's any more or less pythonic than just using two different lists.
Posts: 8,089
Threads: 154
Joined: Sep 2016
Feb-28-2017, 09:09 PM
(This post was last modified: Feb-28-2017, 10:02 PM by buran.)
for me for number in numbers loop is the best and most pythonic in this case. while numbers is better than while len(numbers)>0 , but still you still need to use pop() (inefficient compared to the for loop - it will make difference if long list, because you change and reindex the list with every iteration). if you HAVE TO, then use collections.deque , especially for long lists.
also I don't like comparison to 0.
key = 'odd' if num % 2 else 'even' By the way, I don't like ternary conditional operator and use it only in really trivial cases (e.g. in this case it is OK).
numbers = [12, 37, 5, 42, 8, 3]
odd=[]
even=[]
for num in numbers:
if num % 2:
odd.append(num)
else:
even.append(num) following is also nice, but maybe not that explicit
from collections import defaultdict
numbers = [12, 37, 5, 42, 8, 3]
separated = defaultdict(list)
for num in numbers:
separated[num%2].append(num)
Posts: 2,954
Threads: 48
Joined: Sep 2016
Feb-28-2017, 09:18 PM
(This post was last modified: Feb-28-2017, 09:19 PM by wavic.)
In [1]: import numpy as np
In [2]: nums = np.array([12, 37, 5, 42, 8, 3])
In [3]: even, odd = nums[nums % 2 == 0], nums[nums % 2 == 1]
In [4]: print(even, odd)
[12 42 8] [37 5 3] However I have tried a different apporach but strangely it didn't work. Eight is missing from the even list. And I don't know why. Here I pop() a number and put it to the even list if some condition. So the original list sould contain only odd numbers at the end. Doesn't work
In [1]: numbers = [12, 37, 5, 42, 8, 3]
In [2]: even = [numbers.pop(numbers.index(n)) for n in numbers if n % 2 == 0]
In [3]: even
Out[3]: [12, 42]
Posts: 8,089
Threads: 154
Joined: Sep 2016
Feb-28-2017, 09:34 PM
(This post was last modified: Feb-28-2017, 09:37 PM by buran.)
in the first example - you iterate twice over the array.
in the second example you change the list over which you iterate in the loop (in this case - in the comprehension) - that's big NO NO
see, it's equivalent to:
numbers = [12, 37, 5, 42, 8, 3]
even = []
print numbers
print 'enter the loop'
for n in numbers:
print 'index: {}, number: {}'.format(numbers.index(n), n)
if not n%2:
numbers.pop(numbers.index(n))
even.append(n)
print numbers
print 'exit from the loop'
print even Output: [12, 37, 5, 42, 8, 3]
enter the loop
index: 0, number: 12
[37, 5, 42, 8, 3]
index: 1, number: 5
[37, 5, 42, 8, 3]
index: 2, number: 42
[37, 5, 8, 3]
index: 3, number: 3
[37, 5, 8, 3]
exit from the loop
[12, 42]
that's why, if use while numbers loop, you always pop the element with index 0, still not good practice because you change the array over which you iterate in the loop
Posts: 2,954
Threads: 48
Joined: Sep 2016
Well, I pop() the current element not the next one. How can run the it step by step and see what is happening?
Posts: 3,458
Threads: 101
Joined: Sep 2016
Why would you mutate a list your currently iterating over?
(ants are bugs, yo)
Posts: 8,089
Threads: 154
Joined: Sep 2016
Feb-28-2017, 09:46 PM
(This post was last modified: Feb-28-2017, 09:55 PM by buran.)
(Feb-28-2017, 09:38 PM)wavic Wrote: Well, I pop() the current element not the next one.
Note that when you iterate over the list, actually under the hood you iterate over the indexes.
(Feb-28-2017, 09:38 PM)wavic Wrote: Well, I pop() the current element not the next one.
How can run the it step by step and see what is happening?
Look at my code - I expanded the list comprehension for you.
But if you prefer
http://www.pythontutor.com/
Posts: 687
Threads: 37
Joined: Sep 2016
Warning: using a comprehension for the side effects should only be attempted by trained professionals.
numbers = [12, 37, 5, 42, 8, 3]
even,odd=[],[]
_=[[even,odd][i%2].append(i) for i in numbers]
Unless noted otherwise, code in my posts should be understood as "coding suggestions", and its use may require more neurones than the two necessary for Ctrl-C/Ctrl-V.
Your one-stop place for all your GIMP needs: gimp-forum.net
|