Function to find the index of the beginning and end of the longest run in a list

前端 未结 3 645
抹茶落季
抹茶落季 2021-01-29 10:16

I\'m trying to write code that finds the longest run in a list of Boolean values and return the index of the first and last value of that run. For example, if L is [False, Fals

相关标签:
3条回答
  • 2021-01-29 10:48

    A more faster iterative version with itertools.groupby feature:

    from itertools import groupby
    
    def get_longest_run(lst):
        curr_len, run_span = 0, 0
        for k, gr in groupby(lst):
            len_ = len(list(gr))
            if (run_span and len_ > (run_span[1] + 1) - run_span[0]) or len_ > curr_len:
                run_span = (curr_len, curr_len + len_ - 1)
            curr_len += len_
    
        return run_span
    
    lst = [False, False, True, False, False, False, False, True, True, False, False]
    print(get_longest_run(lst))   # (3, 6)
    

    Time performance comparison (to previous answer):

    In [144]: lst = [False, False, True, False, False, False, False, True, True, False, False]                                   
    
    In [145]: def get_longest_run_deniel(lst): 
         ...:     start = 0 
         ...:     runs = [] 
         ...:     for key, run in groupby(lst): 
         ...:         length = sum(1 for _ in run) 
         ...:         runs.append((start, start + length - 1)) 
         ...:         start += length 
         ...:  
         ...:     result = max(runs, key=lambda x: x[1] - x[0]) 
         ...:     return result 
         ...:                                                                                                                    
    
    In [146]: def get_longest_run(lst): 
         ...:     curr_len, run_span = 0, 0 
         ...:     for k, gr in groupby(lst): 
         ...:         len_ = len(list(gr)) 
         ...:         if (run_span and len_ > (run_span[1] + 1) - run_span[0]) or len_ > curr_len: 
         ...:             run_span = (curr_len, curr_len + len_ - 1) 
         ...:         curr_len += len_ 
         ...:  
         ...:     return run_span 
         ...:                                                                                                                    
    
    In [147]: %timeit get_longest_run_deniel(lst)                                                                                
    6.06 µs ± 168 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    In [148]: %timeit get_longest_run(lst)                                                                                       
    3.67 µs ± 131 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    0 讨论(0)
  • 2021-01-29 10:49

    Use itertools.groupby:

    from itertools import groupby
    
    values = [False, False, True, False, False, False, False, True, True, False, False]
    
    start = 0
    runs = []
    for key, run in groupby(values):
        length = sum(1 for _ in run)
        runs.append((start, start + length - 1))
        start += length
    
    result = max(runs, key=lambda x: x[1] - x[0])
    print(result)
    

    Output

    (3, 6)
    
    0 讨论(0)
  • 2021-01-29 11:07

    You can keep track of the starting index and the length of the longest run so far, as well as the starting index of the current run, and if the current index minus the starting index of the current run is greater than the length of the longest run so far, make the current starting index and the said length the new starting index and the length of the longest run:

    def longest_false(L):
        start = max_start = None
        max_size = -1
        for i, v in enumerate(L):
            if v:
                start = None
            else:
                if start is None:
                    start = i
                if i - start > max_size:
                    max_start = start
                    max_size = i - start
        if max_start is None:
            return None, None # in case there is no False at all in the given list
        return max_start, max_start + max_size
    
    0 讨论(0)
提交回复
热议问题