Reputation: 147
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?
Upvotes: 1
Views: 1455
Reputation: 5148
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]
Upvotes: 2
Reputation: 17911
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)
Upvotes: 0
Reputation: 95
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)
Upvotes: 1
Reputation: 4284
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]
Upvotes: 1
Reputation: 782785
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))
Upvotes: 1