What is the Pythonic way to find the longest common prefix of a list of lists?

后端 未结 6 698
温柔的废话
温柔的废话 2020-12-03 07:27

Given: a list of lists, such as [[3,2,1], [3,2,1,4,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]

Todo: Find the longest common

相关标签:
6条回答
  • 2020-12-03 07:56

    I am not sure how pythonic it is

    from itertools import takewhile,izip
    
    x = [[3,2,1], [3,2,1,4,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]
    
    def allsame(x):
        return len(set(x)) == 1
    
    r = [i[0] for i in takewhile(allsame ,izip(*x))]
    
    0 讨论(0)
  • 2020-12-03 08:03

    os.path.commonprefix() works well for lists :)

    >>> x = [[3,2,1], [3,2,1,4,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]
    >>> import os
    >>> os.path.commonprefix(x)
    [3, 2, 1]
    
    0 讨论(0)
  • 2020-12-03 08:07

    Here's an alternative way using itertools:

    >>> import itertools
    >>> L = [[3,2,1,4], [3,2,1,4,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]
    >>> common_prefix = []
    >>> for i in itertools.izip(*L):
    ...    if i.count(i[0]) == len(i):
    ...       common_prefix.append(i[0])
    ...    else:
    ...       break
    ... 
    >>> common_prefix
    [3, 2, 1]
    

    Not sure how "pythonic" it might be considered though.

    0 讨论(0)
  • 2020-12-03 08:07

    An modernized Vertical scan solution using a generator expression and Python 3's builtin zip:

    lst = [[3,2,1], [3,2,1,1,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]
    
    next(zip(*(x for x in zip(*lst) if len(set(x)) == 1)))
    # (3, 2, 1)
    

    See also a related Leetcode problem - Longest Common Prefix.

    0 讨论(0)
  • 2020-12-03 08:19

    Given your example code, you seem to want a version of reduce(set.intersection, map(set, l)) that preserves the initial order of the first list.

    This requires algorithmic improvements, not stylistic improvements; "pythonic" code alone won't do you any good here. Think about the situation that must hold for all values that occur in every list:

    Given a list of lists, a value occurs in every list if and only if it occurs in nlist lists, where nlist is the total number of lists.

    If we can guarantee that each value occurs only once in every list, then the above can be rephrased:

    Given a list of lists of unique items, a value occurs in every list if and only if it occurs nlist times total.

    We can use sets to guarantee that the items in our lists are unique, so we can combine this latter principle with a simple counting strategy:

    >>> l = [[3,2,1], [3,2,1,4,5], [3,2,1,8,9], [3,2,1,5,7,8,9]]
    >>> count = {}
    >>> for i in itertools.chain.from_iterable(map(set, l)):
    ...     count[i] = count.get(i, 0) + 1
    ...     
    

    Now all we have to do is filter the original list:

    >>> [i for i in l[0] if count[i] == len(l)]
    [3, 2, 1]
    
    0 讨论(0)
  • 2020-12-03 08:21

    It is inefficient as it doesn't early-out as soon as a mismatch is found, but its tidy:

    ([i for i,(j,k) in enumerate(zip(a,b)) if j!=k] or [0])[0]
    
    0 讨论(0)
提交回复
热议问题