【问题标题】:Obtain a list containing string elements excluding elements prefixed with any other element from initial list获取包含字符串元素的列表,不包括以初始列表中的任何其他元素为前缀的元素
【发布时间】:2015-07-23 02:10:40
【问题描述】:

我在过滤字符串列表时遇到了一些问题。我发现了一个类似的问题here,但这不是我需要的。

输入列表是:

l = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']

预期的结果是

['ab', 'xc', 'sdfdg']

结果中项目的顺序并不重要

过滤功能必须很快,因为列表的大小很大

我目前的解决方案是

l = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']
for i in range(0, len(l) - 1):
    for j in range(i + 1, len(l)):
        if l[j].startswith(l[i]):
            l[j] = l[i]
        else:
            if l[i].startswith(l[j]):
                l[i] = l[j]

print list(set(l)) 

编辑

在对大输入数据进行多次测试后,列出 1500000 个字符串,我对此的最佳解决方案是:

def filter(l):
    if l==[]:
        return []
    l2=[]
    l2.append(l[0])
    llen = len(l)
    k=0
    itter = 0
    while k<llen:
        addkelem = ''
        j=0
        l2len = len(l2)
        while j<l2len:
            if (l2[j].startswith(l[k]) and l[k]!= l2[j]):
                l2[j]=l[k]
                l.remove(l[k])
                llen-=1
                j-=1
                addkelem = ''
                continue
            if (l[k].startswith(l2[j])):
                addkelem = ''
                break
            elif(l[k] not in l2):
                addkelem = l[k]
            j+=1
        if addkelem != '':
            l2.append(addkelem)
            addkelem = ''
        k+=1
    return l2

执行时间约为 213 秒

Sample imput data - 每一行都是列表中的一个字符串

【问题讨论】:

  • 生成的顺序重要吗?我的意思是算法应该稳定并保持原始顺序吗?
  • 输出顺序不重要,过滤和执行时间很关键
  • 查看我的答案,在我的 2.7 GHz 计算机上,1.500.000 个元素大约需要 1.5 秒。

标签: python string list python-2.7 filtering


【解决方案1】:

我相信以下很可能是最有效的。

from sortedcontainers import SortedSet
def prefixes(l) :
    rtn = SortedSet()
    for s in l:
        rtn.add(s)
        i = rtn.index(s)
        if (i > 0 and s.startswith(rtn[i-1])):
            rtn.remove(s)
        else :
            j = i+1
            while (j < len(rtn) and rtn[j].startswith(s)):
                j+=1
            remove = rtn[i+1:j]
            for r in remove:
                rtn.remove(r)
    return list(rtn)

我相信最重要的情况可能是输入文件非常长,输出文件要小得多。此解决方案避免将整个输入文件保存在内存中。如果输入文件已排序,则它的 rtn 参数永远不会比最终返回的文件长。此外,它还演示了“维护一个对目前看到的数据有效的解决方案,并将该解决方案扩展到对每条新数据都有效”的模式。这是一个让您熟悉的很好的模式。

【讨论】:

  • 很好的解决方案。样本输入约 10 秒,如果输入列表被打乱,则约 18 秒
  • 与其他人相比如何?我认为,如果您创建一个仍然具有合理大小的输出文件的超大输入文件(例如,通过多次将您的文件连接在一起),我的文件仍然可以很好地扩展。您接受的答案需要能够将整个输入文件保存在内存中,而我的答案更像是内存中的输出文件)。
  • 换句话说,这个解决方案将在任何可迭代对象上运行,包括生成器。
  • 是的,但是这个列表不是从文件中加载的,它是在运行时构建的。我发布此文件仅用于测试并概述输入列表中的数据量。
  • 当然。但我们应该尝试从总体上解决这个问题。我相信对于输入集很大但输出集合理的情况,这种解决方案将是最好的。这是一个需要考虑的重要案例,因为海量数据是真实存在的。
【解决方案2】:

这个算法在我的电脑上0.97秒完成任务,the input file submitted by the author (154MB)

l.sort()

last_str = l[0]
filtered = [last_str]
app      = filtered.append

for str in l:
    if not str.startswith(last_str):
        last_str = str
        app(str)

# Commented because of the massive amount of data to print.
# print filtered

算法很简单:首先按字典顺序对列表进行排序,然后搜索不以列表的第一个字符串为前缀的第一个字符串,然后搜索不以最后一个无前缀字符串为前缀的下一个字符串,等等

如果列表已经排序(您的示例文件似乎已经排序),您可以删除 l.sort() 行,这将导致时间和内存的 O(n) 复杂度。

【讨论】:

  • 快速简单。是最快的解决方案,我喜欢这个
  • 如果优化并做成一个函数,这可能是最好的方法。
  • 优秀的解决方案。关键是append 需要恒定的时间。
  • 比我的解决方案简单得多,我已经把问题复杂化了,你需要 map(str.rstrip.. 文件对象才能得到正确的结果,即 251
  • @PadraicCunningham:感谢您的建议,但作者要求输入是一个列表,输出也是一个列表。而且我不确定在对过滤后的元素执行操作时将整个文件保存在 RAM 中是否真的是最佳选择。
【解决方案3】:

编辑3 经过一番冥想,我写了这个算法。它比基于 Padraic Cunningham 提供的大随机数据集的基于 reduce 的方法快 1k 倍(感谢集)。该算法具有 ~ O(nlogn) 复杂度,尽管还有一些空间用于较小的优化。它也非常节省内存。它大约需要 n 个额外的空间。

def my_filter(l):
    q = sorted(l, reverse=True)
    first = q.pop()
    addfirst = True
    while q:
        candidate = q.pop()
        if candidate == first:
            addfirst = False
            continue
        if not candidate.startswith(first):
            if addfirst:
                yield first
            first, addfirst = candidate, True
    if addfirst:
        yield first

Edit2 这个东西在我的测试中和基于reduce的算法一样快,但是这个比较取决于使用的数据集。我只是将教科书页面解析为单词。该算法基于以下观察。令 A、B 和 C 为字符串,len(A)

def my_filter(l):
    q = sorted(l, key=len)
    prefixed = []
    while q:
        candidate = q.pop()
        if any(candidate.startswith(prefix) for prefix in prefixed):
            continue
        if any(candidate.startswith(string) for string in q):
            prefixed.append(candidate)
        else:
           yield candidate

原帖 这是我提出的原始算法。事实上,它是您算法的简洁版本。

l = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']

res = [string for string in l if sum(not string.startswith(prefix) for prefix in l) == len(l)-1]

演示>>>

print res
# ['ab', 'xc', 'sdfdg']

【讨论】:

  • @TonyYang 它对列表中的 n 项中的每一项进行 n 次比较。在大 O 表示法中,这大约是 n^2。附:我没有考虑 startswith 操作本身的成本,将其视为常数 (O(1))
  • @PadraicCunningham 实际上我想使用 De Bruijn 图。人们可能会获得图形并找到孤立的顶点。那会很漂亮,虽然很慢。
  • @PadraicCunningham 这个问题引起了我的极大关注:D 尽管如此,我还是想出了一个线性算法(如果你不计算排序复杂性的话)。我很高兴知道您对此的看法。
  • 他的解决方案提供了与我们相同的结果,并且在速度上是明显的赢家(我们的解决方案大致相同)
  • @EliKorvigo 我什至无法弄清楚你的工作原理,但它简单快速,不错
【解决方案4】:

解决方案 1(使用 LinkedList)

这是一个非常简单的解决方案,使用排序 (O(n * log(n))) 和 LinkedList - 迭代 (O(n)) 和删除元素 (O(1))。如果您对初始数据进行排序,则元素将以这样的方式排序,即另一个元素的最长前缀元素将与后者相邻。因此,该元素可能会被删除。

这是一个过滤掉排序后的LinkedList的代码:

def filter_out(the_list):
    for element in the_list:
        if element.prev_node and element.get_data().startswith(element.prev_node.get_data()):
            the_list.remove(element)

    return the_list

并像这样使用它:

linked_list = LinkedList(sorted(l))
filter_out(linked_list)

那么您的linked_list 将包含过滤后的数据。

此解决方案将采用O(n * log(n))

这里是LinkedList的实现:

class Node(object):
    def __init__(self, data=None, next_node=None, prev_node=None):
        self.data = data
        self._next_node = next_node
        self._prev_node = prev_node

    def get_data(self):
        return self.data

    @property
    def next_node(self):
        return self._next_node

    @next_node.setter
    def next_node(self, node):
        self._next_node = node

    @property
    def prev_node(self):
        return self._prev_node

    @prev_node.setter
    def prev_node(self, node):
        self._prev_node = node

    def __repr__(self):
        return repr(self.get_data())


class LinkedList(object):
    def __init__(self, iterable=None):
        super(LinkedList, self).__init__()

        self.head = None
        self.tail = None
        self.size = 0

        if iterable:
            for element in iterable:
                self.insert(Node(element))

    def insert(self, node):
        if self.head:
            self.tail.next_node = node
            node.prev_node = self.tail
            self.tail = node
        else:
            self.head = node
            self.tail = node

        self.size += 1

    def remove(self, node):
        if self.size > 1:
            prev_node = node.prev_node
            next_node = node.next_node

            if prev_node:
                prev_node.next_node = next_node
            if next_node:
                next_node.prev_node = prev_node
        else:
            self.head = None
            self.tail = None

    def __iter__(self):
        return LinkedListIter(self.head)

    def __repr__(self):
        result = ''
        for node in self:
            result += str(node.get_data()) + ', '
        if result:
            result = result[:-2]
        return "[{}]".format(result)


class LinkedListIter(object):
    def __init__(self, start):
        super(LinkedListIter, self).__init__()

        self.node = start

    def __iter__(self):
        return self

    def next(self):
        this_node = self.node

        if not this_node:
            raise StopIteration

        self.node = self.node.next_node
        return this_node

解决方案 2(使用集合)

如果算法不需要稳定,即结果列表不需要保持元素的原始顺序,这里是使用set的解决方案。

所以让我们做一些定义:

n - 列表的大小,即元素的数量

m - 列表中字符串元素的最大可能长度

首先,从原来的list l 中初始化一个新的set inter

inter = set(l)

这样我们将删除所有重复的元素,这将简化我们的进一步工作。此外,此操作的平均复杂度为O(n),最差情况下为O(n^2)

然后再创建一个空的set,我们将在其中保存我们的结果:

result = set()

现在让我们检查每个元素,看看我们的inter 集合中是否有后缀:

for elem in inter:                   # This will take at most O(n)
    no_prefix = True
    for i in range(1, len(elem)):    # This will take at most O(m)
        if elem[:i] in inter:        # This will take avg: O(1), worst: O(n)
            no_prefix = False
            continue

    if no_prefix:
        result.add(elem)             # This will take avg: O(1), worst: O(n)

所以现在你在result 中得到了你想要的。

这最后的核心步骤将平均采用O(n * (1 * m + 1)) = O(n * m),在最坏的情况下采用O(n * (m * n + n)) = O(n^2 * (m + 1)),因此如果mn相比微不足道,那么您的平均O(n)和最坏的O(n ^ 2)案例。

复杂性是根据Python provides for the set data structure 计算的。为了进一步优化算法,您可以实现自己的tree-based set 并获得O(n * log(n)) 的复杂度。

【讨论】:

  • 53.2039999962 秒,在具有 3.2 Ghz、i5、16 GB RAM 的 PC 上提供演示输入。不错的解决方案
  • @vasilenicusor 到目前为止你最好的结果是什么?
  • 已优化,请参阅解决方案 1,大约需要 10 秒处理您的数据。
  • 到目前为止,最好的解决方案是@Benoit Esnard 提供的解决方案0.582999944687 seconds
【解决方案5】:

你可以试试这个简短的解决方案。

import re
l = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']
newl=[]
newl.append(l[0])
con=re.escape(l[0])

for i in l[1:]:
    pattern=r"^(?!(?:"+con+r")).*$"
    if re.match(pattern,i):
        newl.append(i)
        con=con+"|"+re.escape(i)


print newl

编辑:对于长列表使用

import re
l = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']
newl=[]
newl.append(l[0])
con=re.escape(l[0])

for i in l[1:]:
    for x in re.split("\|",con):
        pattern=r"^(?="+x+r").*$"
        if re.match(pattern,i):
            break
    else:
        newl.append(i)
        con=con+"|"+re.escape(i)


print newl

【讨论】:

  • 嗨,这可以使用简单的字符串,但不能使用像 C:\~sqltmp\express\xmlrw.dll 这样的字符串,正则表达式模式将是 ^(?!(?:C:\~sqltmp\express\xmlrw.dll)).*$ 并会引发错误 invalid expressionsre_constants.error: bogus escape: '\\x'
  • 因为con的大小增长很快,经过582次迭代后pattern的长度为39615,并且会提升OverflowErrorregular expression code size limit exceeded。测试使用来自soft2u.ro/out.txt的样本数据
  • 因为解决方案受限于输入数据的大小。见我之前的评论。请为您的解决方案添加修复程序,否决票将被删除
  • 现在看起来更好
  • 请注意使用正则表达式非常耗时。该脚本在 15 分钟后仍在运行,示例演示输入来自 soft2u.ro/out.txt :(
【解决方案6】:

您可以按首字母对项目进行分组,然后只搜索子列表,任何字符串都不能以子字符串开头,除非它至少具有相同的首字母:

from collections import defaultdict

def find(l):
    d = defaultdict(list)
    # group by first letter
    for ele in l:
        d[ele[0]].append(ele)
    for val in d.values():
        for v in val:
            # check each substring in the sublist
            if not any(v.startswith(s) and v != s  for s in val):
                yield v

print(list(find(l)))
['sdfdg', 'xc', 'ab']

这会正确过滤单词,从下面的代码中可以看出,reduce 函数没有,'tool' 不应该出现在输出中:

In [56]: l = ["tool",'ab',"too", 'xc', 'abb',"toot", 'abed',"abel", 'sdfdg', 'abfdsdg', 'xccc',"xcew","xrew"]

In [57]: reduce(r,l)
Out[57]: ['tool', 'ab', 'too', 'xc', 'sdfdg', 'xrew']

In [58]: list(find(l))
Out[58]: ['sdfdg', 'too', 'xc', 'xrew', 'ab']

它也很有效:

In [59]: l = ["".join(sample(ascii_lowercase, randint(2,25))) for _ in range(5000)]

In [60]: timeit reduce(r,l)
1 loops, best of 3: 2.12 s per loop

In [61]: timeit list(find(l))
1 loops, best of 3: 203 ms per loop

In [66]: %%timeit
..... result = []
....: for element in lst:
....:   is_prefixed = False
....:   for possible_prefix in lst:
....:     if element is not possible_prefix and  element.startswith(possible_prefix):
....:       is_prefixed = True
....:       break
....:   if not is_prefixed:
....:     result.append(element)
....: 
1 loops, best of 3: 4.39 s per loop

In [92]: timeit list(my_filter(l))
1 loops, best of 3: 2.94 s per loop

如果你知道最小字符串长度总是 > 1,你可以进一步优化,同样如果最小长度字符串是 2,那么一个词必须至少有前两个字母:

def find(l):
    d = defaultdict(list)
    # find shortest length string to use as key length
    mn = len(min(l, key=len))
    for ele in l:
        d[ele[:mn]].append(ele)

    for val in d.values():
        for v in val:
            if not any(v.startswith(s) and v != s for s in val):
                yield v


In [84]: timeit list(find(l))
100 loops, best of 3: 14.6 ms per loop

最后,如果您有骗子,您可能希望从列表中过滤掉重复的单词,但您需要保留它们以进行比较:

from collections import defaultdict,Counter

def find(l):
    d = defaultdict(list)
    mn = len(min(l, key=len))
    cn = Counter(l)
    for ele in l:
        d[ele[:mn]].append(ele)
    for val in d.values():
        for v in val:
            if not any(v.startswith(s) and v != s for s in val): 
                # make sure v is not a dupe
                if cn[v] == 1:
                    yield v

因此,如果速度很重要,那么使用上述代码的一些变体的实现将比您的幼稚方法快得多。内存中存储的数据也更多,因此您也应该考虑到这一点。

为了节省内存,我们可以为每个 val/sublist 创建一个计数器,这样我们一次只存储一个计数器字典:

def find(l):
    d = defaultdict(list)
    mn = len(min(l, key=len))
    for ele in l:
        d[ele[:mn]].append(ele)
    for val in d.values():
        # we only need check each grouping of words for dupes
        cn = Counter(val)
        for v in val:
            if not any(v.startswith(s) and v != s for s in val):
                if cn[v] == 1:
                    yield v

每个循环创建一个字典会增加 5 毫秒,所以对于 5k 个单词来说仍然是

如果数据已排序,reduce 方法应该可以工作:

 reduce(r,sorted(l)) # -> ['ab', 'sdfdg', 'too', 'xc', 'xrew']

为了明确行为之间的区别:

In [202]: l = ["tool",'ab',"too", 'xc', 'abb',"toot", 'abed',
             "abel", 'sdfdg', 'abfdsdg', 'xccc',"xcew","xrew","ab"]

In [203]: list(filter_list(l))
Out[203]: ['ab', 'too', 'xc', 'sdfdg', 'xrew', 'ab']

In [204]: list(find(l))
Out[204]: ['sdfdg', 'too', 'xc', 'xrew', 'ab', 'ab']

In [205]: reduce(r,sorted(l))
Out[205]: ['ab', 'sdfdg', 'too', 'xc', 'xrew']

In [206]: list(find_dupe(l))
Out[206]: ['too', 'xrew', 'xc', 'sdfdg']

In [207]: list(my_filter(l))
Out[207]: ['sdfdg', 'xrew', 'too', 'xc']
In [208]: "ab".startswith("ab")
Out[208]: True

所以ab 重复了两次,因此使用集合或字典而不跟踪ab 出现的次数意味着我们认为没有其他元素满足条件ab"ab".startswith(other ) == True,即我们可以看到是不正确的。

您还可以使用 itertools.groupby 根据最小索引大小进行分组:

def find_dupe(l):
    l.sort()
    mn = len(min(l, key=len))
    for k, val in groupby(l, key=lambda x: x[:mn]):
        val = list(val)
        for v in val:
            cn = Counter(val)
            if not any(v.startswith(s) and v != s for s in val) and cn[v] == 1:
                yield v

根据您的 cmets,如果您认为 "dd".startswith("dd") 不应该是重复元素的 True,我们可以调整我的第一个代码:

l = ['abbb', 'xc', 'abb', 'abed', 'sdfdg', 'xc','abfdsdg', 'xccc', 'd','dd','sdfdg', 'xc','abfdsdg', 'xccc', 'd','dd']


def find_with_dupe(l):
    d = defaultdict(list)
    # group by first letter
    srt = sorted(set(l))
    ind = len(srt[0])
    for ele in srt:
        d[ele[:ind]].append(ele)
    for val in d.values():
        for v in val:
            # check each substring in the sublist
            if not any(v.startswith(s) and v != s for s in val):
                yield v


print(list(find_with_dupe(l)))

['abfdsdg', 'abed', 'abb', 'd', 'sdfdg', 'xc']

在随机文本样本上运行的时间只是您自己的代码运行时间的一小部分:

In [15]: l = open("/home/padraic/Downloads/sample.txt").read().split()

In [16]: timeit list(find(l))                                         
100 loops, best of 3: 19 ms per loop

In [17]: %%timeit
   ....: l = open("/home/padraic/Downloads/sample.txt").read().split()
   ....: for i in range(0, len(l) - 1):
   ....:     for j in range(i + 1, len(l)):
   ....:         if l[j].startswith(l[i]):
   ....:             l[j] = l[i]
   ....:         else:
   ....:             if l[i].startswith(l[j]):
   ....:                 l[i] = l[j]
   ....: 

1 loops, best of 3: 4.92 s per loop

两者都返回相同的输出:

In [41]: l = open("/home/padraic/Downloads/sample.txt").read().split()

In [42]:  
for i in range(0, len(l) - 1):
    for j in range(i + 1, len(l)):
        if l[j].startswith(l[i]):
            l[j] = l[i]
        else:
            if l[i].startswith(l[j]):
                l[i] = l[j]
   ....:                 


In [43]: 

In [43]: l2 = open("/home/padraic/Downloads/sample.txt").read().split()

In [44]: sorted(set(l)) == sorted(find(l2))
Out[44]: True

【讨论】:

  • 嗨帕德莱克。你愿意测试我的答案吗?我想看看它如何在同一台机器上使用相同的数据与其他人进行对比。
  • +1 以获得很好的例子。我已经使用小输入数据测试了您的示例并且可以正常工作。如果数据输入增加,则执行呈指数增长。这也不会捕获重复项。
  • @vasilenicusor,最后一部分肯定会被骗。计数器 dict 计算所有出现的单词,并且不会产生出现两次的单词。你在用什么运行它?
  • 这个脚本应该从一个包含文件路径的大列表中获取,只有唯一的根路径(文件夹文件)。例如 ['a:/dir1','a:/dir1/file1.txt','a:/dir1/dir2','a:/dir4/file4.tx', 'a:/dir4/file4.txt' ] 结果是 ['a:/dir1','a:/dir4/file4.tx']
  • @Padraic Cunningham 获取用于测试脚本的示例数据,使用包含 HDD 路径的列表 - 我使用 dir "C:*" /s/b > e:/out.txt 然后加载列表中 out.tx 中的每一行。在我的情况下,我有 1498136 个文件。并且脚本在 10 分钟后仍在运行 :) 在具有 I5 3.2 GHz 和 16 GB RAM 的 PC 上具有 214 MB RAM 和 30% CPU
【解决方案7】:
from collections import Counter


def filter_list(mylist):

    longest_string = len(max(mylist, key=len))

    set_list = [set(filter(lambda x: len(x) == i, mylist))
                for i in range(1, longest_string)]

    def unique_starts_with_filter(string):
        for i in range(1, len(string)):
            if string[:i] in set_list[i-1]: return False
        return True

    cn = Counter(mylist)
    mylist = filter(lambda x: cn[x] == 1, mylist)

    return filter(unique_starts_with_filter, mylist)

(再次)编辑风格和非常小的优化

【讨论】:

  • @PadraicCunningham 如果您可以使用与其他人相同的数据和机器为我进行测试,那将是很酷的。我认为应该是 O(n)
  • 好的,非常感谢。而不是调试它,我想我会把它留在那里,因为你的回答非常彻底。如果 nut 实现不涉及某个地方的集合,我会感到惊讶,因为成员资格测试是 O(1)(尽管我猜想 defaultdict 也是如此?)
  • 如果没有像我的第一个答案这样的骗子,你的效果很好。使用 set 或 dict 的问题是,如果一个单词出现两次,它将被视为唯一,如果您按照我的回答添加了反检查,我想您的也应该涵盖所有情况
  • 是的,但您没有删除它们。如果您有两个"abc"'s,您的代码将保留一个
  • "abc".startswith("abc") -&gt; True,除非 OP 只想考虑子字符串匹配,否则应该删除它,我留下了几个不同的版本,因为不知道完整的实现细节
【解决方案8】:
lst = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']
result = []

for element in lst:
  is_prefixed = False
  for possible_prefix in lst:
    if element is not possible_prefix and element.startswith(possible_prefix):
      is_prefixed = True
      break
  if not is_prefixed:
    result.append(element)

这是一些实验性的多线程版本:

好好测试一下!

import thread
import math
import multiprocessing

list = ['ab', 'xc', 'abb', 'abed', 'sdfdg', 'abfdsdg', 'xccc']

def get_results(list, thread_num, num_of_threads):  
  result = []
  part_size = int(math.ceil(len(list) * 1.0 / num_of_threads))
  for element in list[part_size * thread_num: part_size * (thread_num + 1)]:    
    is_prefixed = False
    for possible_prefix in list:
      if element is not possible_prefix and     element.startswith(possible_prefix):
    is_prefixed = True
    if not is_prefixed:
      result.append(element)
  return result

num_of_threads = multiprocessing.cpu_count()
results = []
for t in xrange(num_of_threads):  
  thread.start_new_thread(lambda list: results.extend(get_results(list, t, num_of_threads)), (list,))

【讨论】:

  • 7k 刺的列表需要 8 秒
  • 现在是2.96 s per loop
  • 够了吗?您需要多久运行一次?
  • 您的代码似乎检查了所有可能的前缀。我在第一个前缀匹配后转到下一个元素
【解决方案9】:

使用reduce函数的解决方案:

def r(a, b):
    if type(a) is list:
        if len([z for z in a if b.startswith(z)]) == 0:
            a.append(b)
        return a
    if a.startswith(b):
        return b
    if b.startswith(a):
        return a
    return [a, b]

print reduce(r, l)

可能[z for z in a if b.startswith(z)]部分还可以进一步优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-17
    • 2020-03-27
    • 2021-10-31
    • 2021-11-26
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多