简体   繁体   中英

Finding sequence of consecutive numbers on lists

I have lists of the form

[[143], [144, 210, 270], [145]]

with arbitrary number sublists of arbitrary length.

I want build a function that checks if there is a sequence of consecutive (ascending) numbers, picking up one element of each list. The first element of the sequence should be in the first list, the second in the second and so on. If a sequence exists, it should return the sequence. It is not needed to find every possible sequence. If a sequence does not exist, then returns 'fail' .

For instance, in the example above, the function should output a list [143,144,145] .

I wrote a code but it only works partially. The code is

def pattern(example):
    index = [0 for t in example]
    stop = min([len(t) for t in example])
    i=0
    while i < stop:
        attempt = [0 for t in example]
        j = 0
        i+1
        while j < len(example):
            attempt[j] = example[j][index[i]]
            try:
                if example[j+1][index[j+1]] - example[j][index[j]] == 1:
                    j+=1
                    index[j]+=1
                else:
                    break
            except:
                break
        if attempt[-1] != 0:
            return attempt
        else:
            return 'fail'

It only works with 2 sublists and I cannot figure out why. Any help?

You can greatly simplify your code by repeatedly looking for the next number in the next list .

def find( list_of_lists ):
    for element in list_of_lists[0]:
        start = element
        next = element
        for list in list_of_lists[1:]:
            next+=1
            print( "looking for {} in {}".format(next, list))
            if not next in list:
                return 'fail'
    return [x for x in range(start,next+1)]

a = [[143], [144, 210, 270], [145]]

find(a)
looking for 144 in [144, 210, 270]
looking for 145 in [145]

[143, 144, 145]

Edit: a corrected version

def find( list_of_lists ):
    num = len(list_of_lists)
    for start in list_of_lists[0]:
        try:
            print( "starting with", start )
            next = start
            last = start + num - 1
            for list in list_of_lists[1:]:
                next+=1
                print( "looking for {} in {}".format(next, list))
                if not next in list:
                    raise KeyError()
                elif next == last:
                    return [x for x in range(start,next+1)]
          except KeyError:
              pass
    return 'fail'

find(a)
starting with 1
looking for 2 in [3, 2, 6]
looking for 3 in [5, 7, 4]
starting with 3
looking for 4 in [3, 2, 6]
starting with 5
looking for 6 in [3, 2, 6]
looking for 7 in [5, 7, 4]

[5, 6, 7]

You can use chain to flat your list.

from itertools import chain


def find_consecutive():
    my_list = [[143], [144, 210, 270], [145]]

    flatten_list = list(chain.from_iterable(my_list))

    for idx, item in enumerate(flatten_list):
        current = item
        preserved_items = [item]

        for _idx, _item in enumerate(flatten_list[idx + 1:]):
            if current + 1 == _item:
                current = _item
                preserved_items.append(_item)

        if len(preserved_item) > 1:
            return preserved_items

    return 'fail'


if __name__ == '__main__':
    print(f"consecutive: {find_consecutive()}")

Output:

consecutive: [143, 144, 145]

Use itertools.product to get the cross product of all the sublists, and test if any of them is a consecutive sequence.

import itertools as it

def pattern(example):
    for l in it.product(*example):
        if is_consecutive(l):
            return l
    return 'fail'

def is_consecutive(l):
    return all(l[i] == l[i+1] - 1 for i in range(len(l)-1))

I like to try this without using imported libraries as a learning experience.

I took this approach. First I simplified your initial list so I only had one list to work in.

Then I compared items in the list to see if the difference between them was 1. The issue I ran into was I'd get duplicates (144 for example) which I removed with dict functions.

x = [[133], [144, 134, 136], [135]]
y = []
z = []

def isOne(itm, lst):
    pos = 0
    for stuff in lst:
        sm = stuff - itm
        if sm == 1:
            return pos
        else:
            pos = pos + 1
    return 0



for itms in x:
    for itms2 in itms:
        y.append(itms2)


for itms in y:
    x = isOne(itms, y)
    if x > 0:
      z.append(itms)
      z.append(y[x])

z = list(dict.fromkeys(z))


print(z)

You can use the function chain() :

from itertools import chain

it = chain.from_iterable(lst)
# add the first item from the iterator to the list
result = [next(it)]

for i in it:
    if result[-1] == i - 1:
        result.append(i)

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