代码之家  ›  专栏  ›  技术社区  ›  None

使用Python测试一个列表是否包含另一个列表

  •  41
  • None  · 技术社区  · 16 年前

    如何测试一个列表是否包含另一个列表(即它是一个连续的子序列)。假设有一个名为contains的函数:

    contains([1,2], [-1, 0, 1, 2]) # Returns [2, 3] (contains returns [start, end])
    contains([1,3], [-1, 0, 1, 2]) # Returns False
    contains([1, 2], [[1, 2], 3]) # Returns False
    contains([[1, 2]], [[1, 2], 3]) # Returns [0, 0]
    

    编辑:

    contains([2, 1], [-1, 0, 1, 2]) # Returns False
    contains([-1, 1, 2], [-1, 0, 1, 2]) # Returns False
    contains([0, 1, 2], [-1, 0, 1, 2]) # Returns [1, 3]
    
    13 回复  |  直到 6 年前
        1
  •  20
  •   Dave Kirby    16 年前

    以下是我的版本:

    def contains(small, big):
        for i in xrange(len(big)-len(small)+1):
            for j in xrange(len(small)):
                if big[i+j] != small[j]:
                    break
            else:
                return i, i+len(small)
        return False
    

    因为在他的注释中,Andrew,think,is,in,the,start,of,the,and,think,as,the,start,of,and,因为他在评论的开头和结尾都是。它不切片任何子列表,因此应该是合理有效的。

    这是新手的兴趣所在 else clause on the for statement

    这与在字符串中查找子字符串相同,因此对于大型列表,实现类似于 Boyer-Moore algorithm .

        2
  •  62
  •   SiHa Yousef_Shamshoum    8 年前

    如果所有项目都是唯一的,则可以使用集合。

    >>> items = set([-1, 0, 1, 2])
    >>> set([1, 2]).issubset(items)
    True
    >>> set([1, 3]).issubset(items)
    False
    
        3
  •  27
  •   renan-eccel Ben    6 年前

    all() 和 any() 函数来执行此操作。 big 包含中的所有元素 small

    result = all(elem in big for elem in small)
    

    检查是否 小的 包含中的任何元素

    result = any(elem in big for elem in small)
    

    变量结果将是布尔值(TRUE/FALSE)。

        4
  •  5
  •   9000    16 年前

    Rabin-Karp algorithm 如果 big 名单真的很大。这个链接甚至包含了几乎可以用Python编写的代码。

        5
  •  3
  •   Grant Paul    16 年前

    编辑后:

    def contains(small, big):
        for i in xrange(1 + len(big) - len(small)):
            if small == big[i:i+len(small)]:
                return i, i + len(small) - 1
        return False
    
        6
  •  2
  •   martineau    16 年前

    这是有效的,而且相当快,因为它使用内置的线性搜索 list.index() 方法和 == 操作员:

    def contains(sub, pri):
        M, N = len(pri), len(sub)
        i, LAST = 0, M-N+1
        while True:
            try:
                found = pri.index(sub[0], i, LAST) # find first elem in sub
            except ValueError:
                return False
            if pri[found:found+N] == sub:
                return [found, found+N-1]
            else:
                i = found+1
    
        7
  •  1
  •   jfs    16 年前

    #!/usr/bin/env python
    
    def list_find(what, where):
        """Find `what` list in the `where` list.
    
        Return index in `where` where `what` starts
        or -1 if no such index.
    
        >>> f = list_find
        >>> f([2, 1], [-1, 0, 1, 2])
        -1
        >>> f([-1, 1, 2], [-1, 0, 1, 2])
        -1
        >>> f([0, 1, 2], [-1, 0, 1, 2])
        1
        >>> f([1,2], [-1, 0, 1, 2])
        2
        >>> f([1,3], [-1, 0, 1, 2])
        -1
        >>> f([1, 2], [[1, 2], 3])
        -1
        >>> f([[1, 2]], [[1, 2], 3])
        0
        """
        if not what: # empty list is always found
            return 0
        try:
            index = 0
            while True:
                index = where.index(what[0], index)
                if where[index:index+len(what)] == what:
                    return index # found
                index += 1 # try next position
        except ValueError:
            return -1 # not found
    
    def contains(what, where):
        """Return [start, end+1] if found else empty list."""
        i = list_find(what, where)
        return [i, i + len(what)] if i >= 0 else [] #NOTE: bool([]) == False
    
    if __name__=="__main__":
        import doctest; doctest.testmod()
    
        8
  •  1
  •   Oleksiy    12 年前

    def contains(subseq, inseq):
        return any(inseq[pos:pos + len(subseq)] == subseq for pos in range(0, len(inseq) - len(subseq) + 1))
    

    这里是我用来调整这一行程序的单元测试:

    https://gist.github.com/anonymous/6910a85b4978daee137f

        9
  •  1
  •   Fabio Lamanna    10 年前

    def contains(a,b):
        str(a)[1:-1].find(str(b)[1:-1])>=0
    
        10
  •  1
  •   Akila D. Perera    8 年前

    这是我的答案。这个函数将帮助您找出B是否是a的子列表。时间复杂度是O(n)。

    `def does_A_contain_B(A, B): #remember now A is the larger list
        b_size = len(B)
        for a_index in range(0, len(A)):
            if A[a_index : a_index+b_size]==B:
                return True
        else:
            return False`
    
        11
  •  0
  •   intuited    16 年前

    我试着尽可能地提高效率。

    their documentation 以及 yield expressions .

    基本上,它从子序列中创建一个值生成器,可以通过发送一个真值来重置这些值。如果发电机复位,它将从 sub .

    sequence 与发电机产量,如果不匹配,重置发电机。

    附属的 如果不重置,就意味着我们找到了匹配的对象。

    str.find False 而不是 -1 .

    进一步说明:我认为,与Python标准一致,返回的tuple的第二个值通常应该高一个。即 "string"[0:2] == "st"

    这取决于这是一个通用例程,还是实现了某个特定的目标;在后一种情况下,最好实现一个通用例程,然后将其包装在一个函数中,该函数可以旋转返回值以符合规范。

    def reiterator(sub):
        """Yield elements of a sequence, resetting if sent ``True``."""
        it = iter(sub)
        while True:
            if (yield it.next()):
                it = iter(sub)
    
    def find_in_sequence(sub, sequence):
        """Find a subsequence in a sequence.
    
        >>> find_in_sequence([2, 1], [-1, 0, 1, 2])
        False
        >>> find_in_sequence([-1, 1, 2], [-1, 0, 1, 2])
        False
        >>> find_in_sequence([0, 1, 2], [-1, 0, 1, 2])
        (1, 3)
        >>> find_in_sequence("subsequence",
        ...                  "This sequence contains a subsequence.")
        (25, 35)
        >>> find_in_sequence("subsequence", "This one doesn't.")
        False
    
        """
        start = None
        sub_items = reiterator(sub)
        sub_item = sub_items.next()
        for index, item in enumerate(sequence):
            if item == sub_item:
                if start is None: start = index
            else:
                start = None
            try:
                sub_item = sub_items.send(start is None)
            except StopIteration:
                # If the subsequence is depleted, we win!
                return (start, index)
        return False
    
        12
  •  0
  •   ChessMaster    14 年前

    我觉得这个很快。。。

    def issublist(subList, myList, start=0):
        if not subList: return 0
        lenList, lensubList = len(myList), len(subList)
        try:
            while lenList - start >= lensubList:
                start = myList.index(subList[0], start)
                for i in xrange(lensubList):
                    if myList[start+i] != subList[i]:
                        break
                else:
                    return start, start + lensubList - 1
                start += 1
            return False
        except:
            return False
    
        13
  •  0
  •   mafonya    8 年前

    大多数答案的问题是,它们适合于列表中唯一的项目。如果项目不是唯一的,并且您仍然想知道是否存在交叉点,则应该对项目进行计数:

    from collections import Counter as count
    
    def listContains(l1, l2):
      list1 = count(l1)
      list2 = count(l2)
    
      return list1&list2 == list1
    
    print( listContains([1,1,2,5], [1,2,3,5,1,2,1]) ) # Returns True
    print( listContains([1,1,2,8], [1,2,3,5,1,2,1]) ) # Returns False
    

    也可以使用 ''.join(list1&list2)

        14
  •  0
  •   Tanjim Ahmed Khan    6 年前
    a=[[1,2] , [3,4] , [0,5,4]]
    print(a.__contains__([0,5,4]))
    

    它提供真实的输出。

    a=[[1,2] , [3,4] , [0,5,4]]
    print(a.__contains__([1,3]))
    

    它提供错误的输出。

    推荐文章