繁体   English   中英

从列表中删除子列表

[英]Remove sublist from list

我想在 Python 中执行以下操作:

A = [1, 2, 3, 4, 5, 6, 7, 7, 7]
C = A - [3, 4]  # Should be [1, 2, 5, 6, 7, 7, 7]
C = A - [4, 3]  # Should not be removing anything, because sequence 4, 3 is not found

所以,我只想从另一个列表中删除子列表(作为序列)的第一次出现。 我怎样才能做到这一点?

编辑:我说的是列表,而不是集合。 这意味着项目是排序(序列)物质(无论是在A和B),以及重复。

使用套装:

C = list(set(A) - set(B))

如果您想保留重复项和/或奥德:

filter_set = set(B)
C = [x for x in A if x not in filter_set]

如果要删除精确序列,这是一种方法:

通过检查子列表是否与所需序列匹配来查找坏索引:

bad_ind = [range(i,i+len(B)) for i,x in enumerate(A) if A[i:i+len(B)] == B]
print(bad_ind)
#[[2, 3]]

由于这将返回一个列表列表,将其展平并将其转换为一个集合:

bad_ind_set = set([item for sublist in bad_ind for item in sublist])
print(bad_ind_set)
#set([2, 3])

现在使用此集合按索引过滤您的原始列表:

C = [x for i,x in enumerate(A) if i not in bad_ind_set]
print(C)
#[1, 2, 5, 6, 7, 7, 7]

上面的bad_ind_set将删除序列的所有匹配项。 如果您只想删除第一个匹配项,则更简单。 您只需要bad_ind的第一个元素(无需展平列表):

bad_ind_set = set(bad_ind[0])

更新:这是一种使用短路for循环查找和删除第一个匹配子序列的方法。 这会更快,因为一旦找到第一个匹配项,它就会爆发。

start_ind = None
for i in range(len(A)):
    if A[i:i+len(B)] == B:
        start_ind = i
        break

C = [x for i, x in enumerate(A) 
     if start_ind is None or not(start_ind <= i < (start_ind + len(B)))]
print(C)
#[1, 2, 5, 6, 7, 7, 7]

我认为这个问题就像一个子字符串搜索,因此可以在这里应用KMPBM子字符串搜索算法 即使您想支持多种模式,也有一些多种模式算法,例如Aho-CorasickWu-Manber等。

下面是由 Python 实现的 KMP 算法,它来自 GitHub Gist。 PS:作者不是我。 我只想分享我的想法。

class KMP:
    def partial(self, pattern):
        """ Calculate partial match table: String -> [Int]"""
        ret = [0]

        for i in range(1, len(pattern)):
            j = ret[i - 1]
            while j > 0 and pattern[j] != pattern[i]:
                j = ret[j - 1]
            ret.append(j + 1 if pattern[j] == pattern[i] else j)
        return ret

    def search(self, T, P):
        """
        KMP search main algorithm: String -> String -> [Int]
        Return all the matching position of pattern string P in S
        """
        partial, ret, j = self.partial(P), [], 0

        for i in range(len(T)):
            while j > 0 and T[i] != P[j]:
                j = partial[j - 1]
            if T[i] == P[j]: j += 1
            if j == len(P):
                ret.append(i - (j - 1))
                j = 0

        return ret

然后用它来计算出匹配的位置,最后移除匹配:

A = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 4]
B = [3, 4]
result = KMP().search(A, B)
print(result)
#assuming at least one match is found
print(A[:result[0]:] + A[result[0]+len(B):])

输出:

[2, 9]
[1, 2, 5, 6, 7, 7, 7, 3, 4]
[Finished in 0.201s]

PS :您也可以尝试其他算法。 除非您非常关心性能,否则@Pault 的答案已经足够好了。

这是另一种方法:

# Returns that starting and ending point (index) of the sublist, if it exists, otherwise 'None'.

def findSublist(subList, inList):
    subListLength = len(subList)
    for i in range(len(inList)-subListLength):
        if subList == inList[i:i+subListLength]:
            return (i, i+subListLength)
    return None


# Removes the sublist, if it exists and returns a new list, otherwise returns the old list.

def removeSublistFromList(subList, inList):
    indices = findSublist(subList, inList)
    if not indices is None:
        return inList[0:indices[0]] + inList[indices[1]:]
    else:
        return inList


A = [1, 2, 3, 4, 5, 6, 7, 7, 7]

s1 = [3,4]
B = removeSublistFromList(s1, A)
print(B)

s2 = [4,3]
C = removeSublistFromList(s2, A)
print(C)
A = [1, 2, 3, 4, 5, 6, 7, 7, 7]
C=[3,4]
A.remove(C[0])
A.remove(C[1])
return A

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM