I have a Python list
num_list = list(range(1,33))
And need every other pair of numbers in the list, like this:
[1, 2, 5, 6, 9, 10 ... ]
I've figured out how to exclude certain indices from the list, like this
num_list[2::3]
> [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
but haven't figured out how to allow it to capture two indices at a time.
CodePudding user response:
You could use enumerate, then filter the index mathematically:
[v for i, v in enumerate(num_list) if i % 4 < 2]
CodePudding user response:
Another solution that should work for you special case using list comprehension
[v for vals in zip(num_list[::4],num_list[1::4]) for v in vals]
CodePudding user response:
You can't do this with just one slice operation. You could do something like
[num_list[j] for i in range(0, len(num_list), 4) for j in (i, i 1)]
Edit: another option is this:
[x for i in range(0, len(num_list), 4) for x in num_list[i:i 2]]
and yet another (lazy) option is
def keep_two_skip_two(it):
it = iter(it)
try:
while True:
yield next(it)
yield next(it)
next(it)
next(it)
except StopIteration:
return
list(keep_two_skip_two(num_list))
CodePudding user response:
Solution 1: Using two excludes:
del num_list[2::4]
del num_list[2::3]
Now your list is:
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]
Solution 2: Using compress and cycle from itertools:
list(compress(num_list, cycle([True, True, False, False]))))
Shorter version:
[*compress(num_list, cycle([1, 1, 0, 0]))]
CodePudding user response:
You could make something a little bit more generic depending on what your pattern looks like. Instead of using an index based condition, you could apply a mask. e.g.
mask = [1, 1, 0, 0]
To create the mask where the values repeat such that it is the same length of your data, you can zip the data alongside itertools.cycle(m). Example:
import itertools
def filter_mask(data, mask):
return [d for d, m in zip(data, itertools.cycle(mask)) if m]
Or use compress as @KellyBundy suggests!
def filter_mask(data, mask):
return list(itertools.compress(data, itertools.cycle(mask)))
Example
>>> data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> filter_mask(data, mask=[1, 0])
[0, 2, 4, 6, 8, 10]
>>> filter_mask(data, mask=[0, 1])
[1, 3, 5, 7, 9]
>>> filter_mask(data, mask=[1, 1, 0, 0])
[0, 1, 4, 5, 8, 9]
>>> filter_mask(data, mask=[1, 0, 1, 1, 0])
[0, 2, 3, 5, 7, 8, 10]
CodePudding user response:
sorted(num_list[0::4] num_list[1::4])
CodePudding user response:
Here's a functional way to achieve this using itertools.chain.from_iterable along with zip on your sliced lists as:
>>> num_list = list(range(1,33))
>>> from itertools import chain
>>> list(chain.from_iterable(zip(num_list[::4], num_list[1::4])))
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]
CodePudding user response:
Using different range objects for two generators:
>>> [x for i in range(1,33,4) for x in range(i, i 2)]
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]
A lazy version that only generates the 2-element ranges on demand:
>>> from itertools import chain
>>> x = chain.from_iterable(range(i, i 2) for i in range(1,33,4))
>>> list(x)
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]
CodePudding user response:
Here is one solution:
num_list = list(range(1,33))
i=0
j=0
new_list = []
for num in num_list:
i =1
if i == 3:
i = 2
j =1
if j == 2:
j=0
i=0
continue
new_list.append(num)
print(new_list)
Output:
[1, 2, 5, 6, 9, 10, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30]
This will iterate through the list and skip 2 items after every 2 items.
It may be easier to read when expanded like this.
