我正在尝试根据主列表对一长串标签进行排序,并且正在努力有效地实现这一点。如下面的示例所示,我想将长列表中与字符串共用一个开头的所有项目组合在一起,然后按照与“主列表”相同的顺序创建一个新列表。
使用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']
答案 0 :(得分:2)
这是一种方法,使用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']
答案 1 :(得分:1)
另一种简单方法:
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']
答案 2 :(得分:0)
要改进的几件事情:
您不需要if fruit in label:
,您只需使用if fruit == label[0:len(fruit)]
,因为您不需要完整的子字符串搜索,只需要开头。
您可以先对labels
进行排序,这样当您找到第一个时,您可以直接添加,直到检查失败并跳过其余部分,因为这样您就可以确定它们了。不再匹配了。显然排序有成本,但它仍然比每次检查所有内容更有效。您需要一份副本,以免丢失您最初如何排序的参考。