简体   繁体   中英

Python grouping items and looping with a step

If I had this list:

y =[a,b,c,d,e,f]

And I want to select a and b , then e and f , what's the syntax for that?

I've tried:

y = [a,b,c,d,e,f,g,h,i,j]
for letter in range(0,len(y),2):
    print(letter)

The result I want is

[a, b, e, f i,j]

But instead I get every second letter:

a
c
e
g
i 

When I've tried using slice notation print(y[:1]) I only get the first two values in the list.

You need to set the step to 4. For every 4 items, you need the first two(3 and 4 are skipped). so:

lst = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

new_list = []
for i in range(0, len(lst), 4):
    new_list.append(lst[i])
    new_list.append(lst[i + 1])

print(new_list)

If the iterable is really just a string/collection of characters:

from textwrap import wrap
from itertools import chain

print(list(chain.from_iterable(wrap("abcdefghij", 2)[::2])))

Output:

['a', 'b', 'e', 'f', 'i', 'j']
>>> 

If it's an arbitrary iterable:

from itertools import islice, chain

def chunk_wise(iterable, chunk_size):
    it = iter(iterable)
    while chunk := list(islice(it, chunk_size)):
        yield chunk

print(list(chain.from_iterable(islice(chunk_wise("abcdefghij", 2), 0, None, 2))))

Output:

['a', 'b', 'e', 'f', 'i', 'j']
>>> 

The most straightforward way is to use a list comprehension with an if-clause ('filter') that will pick the items in your span that you want.

ls = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
ls_spans = [x for i, x in enumerate(ls) if i % 4 in [0,1]]

To tease this out more, what we do is a list comprehension:

ls_spans = [x for x in ls]  # Essentially just copies the list

But we want to select only certain members of a 'span', which we identify as a 4-unit length: ( abcd , efgh , ij in our list).

ls_spans = [x for x in ls if x_is_wanted()]

To do this, since the fact of whether we want x or not is dependent on it's position, we use enumerate to pair each element in the list with an index (the i in the list comprehension below):

ls_spans = [x for i, x in enumerate(ls) if x_is_wanted(i)]

Now, we consider the function x_is_wanted which has to say 'yes' or 'no' ( True or False ) for each element:

def x_is_wanted(i: int) -> bool:
    span_length = 4
    acceptable_positions = [0, 1]  # Remember we are 0-indexed!
    return i % span_length in acceptable_positions  # We use modulo to get the remainder, which is equivalent to the position in the span.

The complete program would probably look like:

def x_is_wanted(i: int) -> bool:
    span_length = 4
    acceptable_positions = [0, 1]  # Remember we are 0-indexed!
    return i % span_length in acceptable_positions    

ls_spans = [x for i, x in enumerate(ls) if x_is_wanted(i)]

But we can more easily inline this, if we don't need to re-use the function:

# Play with these params to see what changes!
span_length = 4
acceptable_positions = [0, 1]
ls = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
ls_spans = [x for i, x in enumerate(ls) if i % span_length in acceptable_positions]
 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM