简体   繁体   中英

Pythonic: Find all consecutive sub-sequences of certain length

I have a list of integers and I want to find all consecutive sub-sequences of length n in this list. For example:

>>> int_list = [1,4,6,7,8,9]
>>> conseq_sequences(int_list, length=3)
[[6,7,8], [7,8,9]]

The best I could come up with is:

def conseq_sequences(self, li, length):
    return [li[n:n+length]
            for n in xrange(len(li)-length+1)
            if li[n:n+length] == range(li[n], li[n]+length)]

This isn't overly readable. Is there any readable pythonic way of doing this?

Here's a more general solution that works for arbitrary input iterables (not just sequences):

from itertools import groupby, islice, tee
from operator import itemgetter

def consecutive_subseq(iterable, length):
    for _, consec_run in groupby(enumerate(iterable), lambda x: x[0] - x[1]):
        k_wise = tee(map(itemgetter(1), consec_run), length)
        for n, it in enumerate(k_wise):
            next(islice(it, n, n), None) # consume n items from it
        yield from zip(*k_wise)

Example:

print(*consecutive_subseq([1,4,6,7,8,9], 3))
# -> (6, 7, 8) (7, 8, 9)

The code uses Python 3 syntax that could be adapted for Python 2 if needed.

See also, What is the most pythonic way to sort dates sequences?

One solution could be as follows:

import numpy # used diff function from numpy, but if not present, than some lambda or other helper function could be used. 

def conseq_sequences(li, length):
    return [int_list[i:i+length] for i in range(0, len(int_list)) if sum(numpy.diff(int_list[i:i+length]))==length-1]

Basically, first, I get consecutive sub-lists of given length from the list, and then check if the sum of the differences of their elements is equal to length - 1 .

Please not that if elements are consecutive, their difference will add up to length - 1 , eg for sub-list [5,6,7] the difference of its elements is [1, 1] and sum of it is 2 .

But to be honest not sure if this solution is clearer or more pythonic than yours.

Just in case you don't have numpy , the diff function can be easly defined as follows:

def diff(l):
  '''For example, when l=[1,2,3] than return is [1,1]'''  
  return [x - l[i - 1] for i, x in enumerate(l)][1:]

Using operator.itemgetter and itertools.groupby

 def conseq_sequences(li, length):
    res = zip(*(li[i:] for i in xrange(length)))
    final = []
    for x in res:
        for k, g in groupby(enumerate(x), lambda (i, x): i - x):
            get_map = map(itemgetter(1), g)
            if len(get_map) == length:
                final.append(get_map)
    return final

Without imports.

def conseq_sequences(li, length):
    res = zip(*(li[i:] for i in xrange(length)))
    final = []
    for ele in res:
        if all(x == y+1 for x, y in zip(ele[1:], ele)):
            final.append(ele)
    return final

Which can be turned into list comprehension:

def conseq_sequences(li, length):
    res = zip(*(li[i:] for i in xrange(length)))
    return [ ele for ele in res if all(x == y+1 for x, y in zip(ele[1:], ele))]
 def condition (tup):
    if tup[0] + 1 == tup[1] and tup[1] + 1 == tup[2] :
        return True
    return False

 def conseq_sequence(li):
   return [x for x in map(None, iter(li), iter(li[1:]), iter(li[2:])) if condition(x)]

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