Python:在另一个列表的成员中查找列表(按顺序)

时间:2010-02-12 09:06:31

标签: list python

如果我有这个:

a='abcdefghij'
b='de'

然后在a:

中找到b
b in a => True

有没有办法用列表做类似的事情? 像这样:

a=list('abcdefghij')
b=list('de')

b in a => False 

“假”结果是可以理解的 - 因为它正确地寻找元素'de',而不是(我碰巧想要它做什么)'d'后跟'e'

这是有效的,我知道:

a=['a', 'b', 'c', ['d', 'e'], 'f', 'g', 'h']
b=list('de')
b in a => True

我可以处理数据以获得我想要的东西 - 但是有一个简短的Pythonic方法吗?

澄清一下:我需要在这里保留排序(b = ['e','d'],应该返回False)。

如果它有帮助,我所拥有的是一个列表列表:这些列表代表有向图中从节点1到节点-x的所有可能路径(受访节点列表):我想要“排除”任何更长路径中的公共路径。 (因此寻找所有不可缩短的“原子”路径,构成所有较长的路径)。

相关

9 个答案:

答案 0 :(得分:11)

我怀疑有更多的pythonic方式,但至少它完成了工作:

l=list('abcdefgh')
pat=list('de')

print pat in l # Returns False
print any(l[i:i+len(pat)]==pat for i in xrange(len(l)-len(pat)+1))

答案 1 :(得分:7)

我认为这会更快 - 它使用C实现list.index来搜索第一个元素,并从那里开始。

def find_sublist(sub, bigger):
    if not bigger:
        return -1
    if not sub:
        return 0
    first, rest = sub[0], sub[1:]
    pos = 0
    try:
        while True:
            pos = bigger.index(first, pos) + 1
            if not rest or bigger[pos:pos+len(rest)] == rest:
                return pos
    except ValueError:
        return -1

data = list('abcdfghdesdkflksdkeeddefaksda')
print find_sublist(list('def'), data)

请注意,这会返回列表中子列表的位置,而不仅仅是TrueFalse。如果您只想要一个bool,可以使用它:

def is_sublist(sub, bigger): 
    return find_sublist(sub, bigger) >= 0

答案 2 :(得分:6)

不知道这是非常pythonic,但我会这样做:

def is_sublist(a, b):
    if not a: return True
    if not b: return False
    return b[:len(a)] == a or is_sublist(a, b[1:])

discussion中提供了更短的解决方案,但它遇到与set解决方案相同的问题 - 它不考虑元素的顺序。

更新:
受MAK的启发,我介绍了更简洁明了的代码版本。

更新: 由于列表中的列表复制,此方法存在性能问题。此外,由于它是递归的,您可能会遇到长列表的递归限制。要消除复制,您可以使用Numpy creates views, not copies个切片。如果遇到性能或递归限制问题,则应使用不带递归的解决方案。

答案 3 :(得分:3)

我计划了接受的解决方案,我早期的解决方案以及带索引的新解决方案。具有指数的人显然是最好的。

编辑:我计划了nosklo的解决方案,它甚至比我想出的要好得多。 :)

def is_sublist_index(a, b):
    if not a:
        return True

    index = 0
    for elem in b:
        if elem == a[index]:
            index += 1
            if index == len(a):
                return True
        elif elem == a[0]:
            index = 1
        else:
            index = 0

    return False

def is_sublist(a, b):
    return str(a)[1:-1] in str(b)[1:-1]

def is_sublist_copylist(a, b):
    if a == []: return True
    if b == []: return False
    return b[:len(a)] == a or is_sublist_copylist(a, b[1:])

from timeit import Timer
print Timer('is_sublist([99999], range(100000))', setup='from __main__ import is_sublist').timeit(number=100)
print Timer('is_sublist_copylist([99999], range(100000))', setup='from __main__ import is_sublist_copylist').timeit(number=100)
print Timer('is_sublist_index([99999], range(100000))', setup='from __main__ import is_sublist_index').timeit(number=100)
print Timer('sublist_nosklo([99999], range(100000))', setup='from __main__ import sublist_nosklo').timeit(number=100)

以秒为单位的输出:

4.51677298546

4.5824368

1.87861895561

0.357429027557

答案 4 :(得分:2)

因此,如果您不关心子集出现的顺序,您可以这样做:

a=list('abcdefghij')
b=list('de')
set(b).issubset(set(a))

True

在您澄清之后进行编辑:如果您需要保留订单,并且列表确实是您问题中的字符,则可以使用:

''.join(a).find(''.join(b)) > 0

答案 5 :(得分:2)

这应该适用于任何列表,保留订单。 正在检查 b a

的子列表
def is_sublist(b,a): 

    if len(b) > len(a):
        return False    

    if a == b:
        return True    

    i = 0
    while i <= len(a) - len(b):
        if a[i] == b[0]:
            flag = True
            j = 1
            while i+j < len(a) and j < len(b):
                if a[i+j] != b[j]:
                    flag = False
                j += 1
            if flag:
                return True
        i += 1
    return False

答案 6 :(得分:1)

>>>''.join(b) in ''.join(a)

True

答案 7 :(得分:0)

不确定您的应用程序有多复杂,但对于列表中的模式匹配,pyparsing非常智能且易于使用。

答案 8 :(得分:-1)

使用列表的字符串表示并删除方括号。 :)

def is_sublist(a, b):
    return str(a)[1:-1] in str(b)
编辑:对,有误报......例如is_sublist([1], [11])。蹩脚的回答。 :)