So I want to create a list which is a sublist of some existing list.
For example,
L = [1, 2, 3, 4, 5, 6, 7]
, I want to create a sublist li
such that li
contains all the elements in L
at odd positions.
While I can do it by
L = [1, 2, 3, 4, 5, 6, 7]
li = []
count = 0
for i in L:
if count % 2 == 1:
li.append(i)
count += 1
But I want to know if there is another way to do the same efficiently and in fewer number of steps.
Yes, you can:
l = L[1::2]
And this is all. The result will contain the elements placed on the following positions (0
-based, so first element is at position 0
, second at 1
etc.):
1, 3, 5
so the result (actual numbers) will be:
2, 4, 6
The [1::2]
at the end is just a notation for list slicing. Usually it is in the following form:
some_list[start:stop:step]
If we omitted start
, the default (0
) would be used. So the first element (at position 0
, because the indexes are 0
-based) would be selected. In this case the second element will be selected.
Because the second element is omitted, the default is being used (the end of the list). So the list is being iterated from the second element to the end.
We also provided third argument (step
) which is 2
. Which means that one element will be selected, the next will be skipped, and so on...
So, to sum up, in this case [1::2]
means:
step=2
, so we are skipping one, as a contrary to step=1
which is default),EDIT: @PreetKukreti gave a link for another explanation on Python's list slicing notation. See here: Explain Python's slice notation
enumerate()
In your code, you explicitly create and increase the counter. In Python this is not necessary, as you can enumerate through some iterable using enumerate()
:
for count, i in enumerate(L):
if count % 2 == 1:
l.append(i)
The above serves exactly the same purpose as the code you were using:
count = 0
for i in L:
if count % 2 == 1:
l.append(i)
count += 1
More on emulating for
loops with counter in Python: Accessing the index in Python 'for' loops
You can make use of bitwise AND operator &
.
Let's see below:
x = [1, 2, 3, 4, 5, 6, 7]
y = [i for i in x if i&1]
>>>
[1, 3, 5, 7]
Bitwise AND operator is used with 1, and the reason it works because, odd number when written in binary must have its first digit as 1. Let's check
23 = 1 * (2**4) + 0 * (2**3) + 1 * (2**2) + 1 * (2**1) + 1 * (2**0) = 10111
14 = 1 * (2**3) + 1 * (2**2) + 1 * (2**1) + 0 * (2**0) = 1110
AND operation with 1 will only return 1 (1 in binary will also have last digit 1), iff the value is odd.
Check the Python Bitwise Operator page for more.
P.S: You can tactically use this method if you want to select odd and even columns in a dataframe. Let's say x and y coordinates of facial key-points are given as columns x1, y1, x2, etc... To normalize the x and y coordinates with width and height values of each image you can simply perform
for i in range(df.shape[1]):
if i&1:
df.iloc[:, i] /= heights
else:
df.iloc[:, i] /= widths
This is not exactly related to the question but for data scientists and computer vision engineers this method could be useful.
Cheers!
I like List comprehensions because of their Math (Set) syntax. So how about this:
L = [1, 2, 3, 4, 5, 6, 7]
odd_numbers = [y for x,y in enumerate(L) if x%2 != 0]
even_numbers = [y for x,y in enumerate(L) if x%2 == 0]
Basically, if you enumerate over a list, you'll get the index x
and the value y
. What I'm doing here is putting the value y
into the output list (even or odd) and using the index x
to find out if that point is odd (x%2 != 0
).
For the odd positions, you probably want:
>>>> list_ = list(range(10))
>>>> print list_[1::2]
[1, 3, 5, 7, 9]
>>>>
list_ = list(range(9)) print(list_[1::2])
Source: Stackoverflow.com