【问题标题】:Sort list based on a subset list (without nested loops)基于子集列表的排序列表(没有嵌套循环)
【发布时间】:2018-03-08 11:31:54
【问题描述】:

我正在尝试根据主列表对一长串标签进行排序,并且正在努力有效地实现这一点。如下面的示例所示,我想将长列表中的所有项目组合在一起,这些项目共享一个共同的字符串开头,然后以与“主列表”相同的顺序创建一个新列表。

使用 Python,我通常会尝试向量化和并行处理数组,但这似乎不适用于基于字符串的数组。

这是我使用嵌套循环的示例和解决方案:

fruits = ['apple', 'banana', 'orange']  # "master list"
labels = ['banana2', 'apple2', 'orange1', 'banana1', 'apple1', 'apple3']  # "long list"
new_list = []
for fruit in fruits:
    for label in labels:
        if fruit in label:
            new_list.append(label)

print(new_list) 然后返回

['apple2', 'apple1', 'apple3', 'banana2', 'banana1', 'orange1']

这可以在没有嵌套循环的情况下完成吗?

为了获得额外的好处,我理想情况下也希望根据字符串中的最终数字对标签进行排序,例如给出结果:['apple1', 'apple2', 'apple3', 'banana1', 'banana2', 'orange1']

【问题讨论】:

    标签: python string loops sorting


    【解决方案1】:

    这是一种方法,使用list.index 导出排序顺序。

    fruits = ['apple', 'banana', 'orange']
    labels = ['banana2', 'apple2', 'orange1', 'banana1', 'apple1', 'apple3']
    
    res = sorted(labels, key=lambda x: fruits.index(x[:-1]))
    
    # ['apple2', 'apple1', 'apple3', 'banana2', 'banana1', 'orange1']
    

    您也可以使用tuple 作为排序键,结合一些正则表达式来分隔任意大小的整数。

    import re
    
    fruits = ['apple', 'banana', 'orange']
    labels = ['banana2', 'apple2', 'orange1', 'banana1', 'apple10', 'apple3']
    
    def sorter(mystr, fruits):
        str_split = re.match(r'([a-z]+)([0-9]+)', mystr, re.I).groups()
        return (fruits.index(str_split[0]), int(str_split[1]))
    
    res2 = sorted(labels, key=lambda x: sorter(x, fruits))
    
    # ['apple2', 'apple3', 'apple10', 'banana1', 'banana2', 'orange1']
    

    【讨论】:

    • 如果列表中是apple10,或者数字进入十位、百位等怎么办?
    【解决方案2】:

    另一种简单的方法:

    import re
    
    fruits = ['apple', 'banana', 'orange']  # "master list"
    labels = ['banana2', 'apple2', 'orange1', 'banana1', 'apple10', 'apple3']  # "long list"
    
    def normal_sort(text):
        return [int(c) if c.isdigit() else c for c in re.split('(\d+)', text)]
    
    def func(x):
        x = " ".join(re.findall("[a-zA-Z]+", x))
        return x
    
    print(sorted(sorted(labels, key=func), key=normal_sort))
    # ['apple2', 'apple3', 'apple10', 'banana1', 'banana2', 'orange1']
    

    【讨论】:

    • @jpp 谢谢。我现在修好了。
    【解决方案3】:

    有几点需要改进:

    • 你不需要if fruit in label:,你可以用if fruit == label[0:len(fruit)],因为你不需要完整的子串搜索,只需要开头。

    • 您可以先对labels 进行排序,这样当您找到第一个时,您可以添加直到检查失败并跳过其余部分,因为这样您就确定它们不会再匹配了。显然排序是有代价的,但它仍然应该比每次都检查所有东西更有效。您需要一份副本,以免丢失有关它们最初排序方式的参考信息。

    【讨论】:

      猜你喜欢
      • 2017-08-24
      • 2021-02-20
      • 1970-01-01
      • 2020-11-24
      • 2020-08-24
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多