简体   繁体   中英

Python finding repeating sequence in list of integers?

I have a list of lists and each list has a repeating sequence. I'm trying to count the length of repeated sequence of integers in the list:

list_a = [111,0,3,1,111,0,3,1,111,0,3,1] 

list_b = [67,4,67,4,67,4,67,4,2,9,0]

list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]

Which would return:

list_a count = 4 (for [111,0,3,1])

list_b count = 2 (for [67,4])

list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])

Any advice or tips would be welcome. I'm trying to work it out with re.compile right now but, its not quite right.

Guess the sequence length by iterating through guesses between 2 and half the sequence length. If no pattern is discovered, return 1 by default.

def guess_seq_len(seq):
    guess = 1
    max_len = len(seq) / 2
    for x in range(2, max_len):
        if seq[0:x] == seq[x:2*x] :
            return x

    return guess

list_a = [111,0,3,1,111,0,3,1,111,0,3,1] 
list_b = [67,4,67,4,67,4,67,4,2,9,0]
list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]

print guess_seq_len(list_a)
print guess_seq_len(list_b)
print guess_seq_len(list_c)
print guess_seq_len(range(500))   # test of no repetition

This gives (as expected):

4
2
10
1

As requested, this alternative gives longest repeated sequence. Hence it will return 4 for list_b. The only change is guess = x instead of return x

def guess_seq_len(seq):
    guess = 1
    max_len = len(seq) / 2
    for x in range(2, max_len):
        if seq[0:x] == seq[x:2*x] :
            guess = x

    return guess

I took Maria 's faster and more stackoverflow-compliant answer and made it find the largest sequence first:

def guess_seq_len(seq, verbose=False):
    seq_len = 1
    initial_item = seq[0]
    butfirst_items = seq[1:]
    if initial_item in butfirst_items:
        first_match_idx = butfirst_items.index(initial_item)
        if verbose:
            print(f'"{initial_item}" was found at index 0 and index {first_match_idx}')
        max_seq_len = min(len(seq) - first_match_idx, first_match_idx)
        for seq_len in range(max_seq_len, 0, -1):
            if seq[:seq_len] == seq[first_match_idx:first_match_idx+seq_len]:
                if verbose:
                    print(f'A sequence length of {seq_len} was found at index {first_match_idx}')
                break
    
    return seq_len

This worked for me.

def repeated(L):
    '''Reduce the input list to a list of all repeated integers in the list.'''
    return [item for item in list(set(L)) if L.count(item) > 1]

def print_result(L, name):
    '''Print the output for one list.'''
    output = repeated(L)
    print '%s count = %i (for %s)' % (name, len(output), output)

list_a = [111, 0, 3, 1, 111, 0, 3, 1, 111, 0, 3, 1]
list_b = [67, 4, 67, 4, 67, 4, 67, 4, 2, 9, 0]
list_c = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
    3, 4, 5, 6, 7, 8, 9, 0, 23, 18, 10
]

print_result(list_a, 'list_a')
print_result(list_b, 'list_b')
print_result(list_c, 'list_c')

Python's set() function will transform a list to a set, a datatype that can only contain one of any given value, much like a set in algebra. I converted the input list to a set, and then back to a list, reducing the list to only its unique values. I then tested the original list for each of these values to see if it contained that value more than once. I returned a list of all of the duplicates. The rest of the code is just for demonstration purposes, to show that it works.

Edit: Syntax highlighting didn't like the apostrophe in my docstring.

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