Rewriting nested if statements in a more pythonic way

I am working on a function that, given a sequence, tries to find the specified sequence inside a list and then should return a list item immediately after the completion of this sequence.

Currently, this code returns a list item immediately after the end of the sequence, however, I am not happy that I have many nested if statements, and I would like to rewrite it, but I cannot figure out how to do this about it, since it not at all like what I have ever written in the past, and I feel a bit out of practice.

def sequence_in_list(seq, lst): m, n = len(lst), len(seq) for i in xrange(m): for j in xrange(n): if lst[i] == seq[j]: if lst[i+1] == seq[j+1]: if lst[i+2] == seq[j+2]: return lst[i+3] 

(My intention is then to extend this function so that if this sequence occurs more than once in the list, it should return the next element that occurred most often after the sequence)

+4
source share
3 answers

Since you are comparing consecutive indexes and think that lst and seq are of the same type, you can use slicing:

 def sequence_in_list(seq, lst): m, n = len(lst), len(seq) for i in xrange(m): for j in xrange(n): if lst[i:i+3] == seq[j:j+3]: return lst[i+3] 

If the sequences have a different look, you must convert them to a general type before performing a comparison (for example, lst[i:i+3] == list(seq[j:j+3]) will work if seq is a string and lst - list).

Alternatively, if the sequences do not support slicing, you can use the built-in all to check for additional conditions:

 def sequence_in_list(seq, lst): m, n = len(lst), len(seq) for i in xrange(m): for j in xrange(n): if all(lst[i+k] == seq[j+k] for k in range(3)): return lst[i+3] 

If you want to extend the check of more than 10 indexes instead of 3, just change range(3) to range(10) .

Side note: your source code will raise an IndexError at some point, since you will get access to list[i+1] , where i may be len(list) - 1 . The above code does not cause errors, since slicing can give a shorter cut than the index difference, meainig, that seq[j:j+3] can have less than 3 elements. If this is a problem, you should adjust the indexes you are iterating over.

One final note: do not use the name list , as it obscures the built-in name.

+1
source

I would do it with a generator and slicing:

 sequence = [1, 2, 3, 5, 1, 2, 3, 6, 1, 2, 3] pattern = [1, 2, 3] def find_item_after_pattern(sequence, pattern): n = len(pattern) for index in range(0, len(sequence) - n): if pattern == sequence[index:index + n]: yield sequence[index + n] for item in find_item_after_pattern(sequence, pattern): print(item) 

And you will get:

 5 6 

The function is not very efficient and will not work for infinite sequences, but it is concise and general.

+2
source

You can combine comprehension of the list with slicing to make the comparison more readable:

 n, m = len(lst), len(seq) [lst[j+3] for i in range(m-2) for j in range(n-2) if seq[i:i+3] == lst[j:j+3]] 

Of course, there are more efficient ways to do this, but it's simple, short and python.

0
source

Source: https://habr.com/ru/post/1492249/


All Articles