3

假设我有以下列表:

List1=['Name1','Name3','Color1','Size2','Color3','Color2','Name2','Size1', 'ID']
List2=['ID','Color1','Color2','Size1','Size2','Name1','Name2']

每个列表将具有名为“ID”变量的元素,然后是 3 个其他类别(名称、颜色和大小),其中每个类别中的元素数量不确定。

我想对这些变量进行排序,但不知道每个类别中有多少具有以下“排序列表”:

SortList=['ID','Name','Size','Color']

我可以获得所需的输出(见下文),尽管我想有更好/更 Pythonic 的方式这样做。

>>> def SortMyList(MyList,SortList):       
...     SortedList=[]       
...     for SortItem in SortList:
...         SortItemList=[]
...         for Item in MyList:
...             ItemWithoutNum="".join([char for char in Item if char.isalpha()])  
...             if SortItem==ItemWithoutNum:
...                 SortItemList.append(Item)
...         if len(SortItemList)>1:
...             SortItemList=[SortItem+str(I) for I in range(1,len(SortItemList)+1)]
...         for SortedItem in SortItemList:
...             SortedList.append(SortedItem)
...     return SortedList
... 
>>> 
>>> SortMyList(List1, SortList)
['ID', 'Name1', 'Name2', 'Name3', 'Size1', 'Size2', 'Color1', 'Color2', 'Color3']
>>> SortMyList(List2, SortList)
['ID', 'Name1', 'Name2', 'Size1', 'Size2', 'Color1', 'Color2']
>>> 

关于如何改进我的方法或代码的任何建议?

4

4 回答 4

5

您可以使用自定义键函数对列表进行排序,该函数返回一个 2 元组,用于初级排序和二级排序。

主要排序是按照您的“标签”的顺序(首先是 ID,然后是名称等)。二级排序是按其后面的数值。

tags = ['ID','Name','Size','Color']
sort_order = { tag : i for i,tag in enumerate(tags) }

def elem_key(x):
    for tag in tags:
        if x.startswith(tag):
            suffix = x[len(tag) : ]
            return ( sort_order[tag],
                     int(suffix) if suffix else None )
    raise ValueError("element %s is not prefixed by a known tag. order is not defined" % x)

list1.sort(key = elem_key)
于 2016-01-19T20:03:10.207 回答
1

您只需提供足够的密钥:

List1.sort( key = lambda x : ('INSC'.index(x[0]),x[-1]))
# ['ID', 'Name1', 'Name2', 'Name3', 'Size1', 'Size2', 'Color1', 'Color2', 'Color3']

元素将按第一个字母排序,然后是最后一个数字(如果存在)。它在这里有效,因为所有第一个字母都是不同的,并且数字最多只有一个数字。

编辑

对于许多数字,更模糊的解决方案:

List1.sort( key =lambda x : ('INSC'.index(x[0]),int("0"+"".join(re.findall('\d+',x)))))
 # ['ID', 'Name1', 'Name2', 'Name10', 'Size1', 'Size2', 'Color1', 'Color2', 'Color3']
于 2016-01-19T20:21:22.687 回答
0

只要您知道 List2 仅包含以 sortList 中的内容开头的字符串,这将有效

List2=['ID','Color4','Color2','Size1','Size2','Name2','Name1']
sortList=['ID','Name','Size','Color']
def sort_fun(x):
    for i, thing in enumerate(sortList):
        if x.startswith(thing):
            return (i, x[len(thing):])

print sorted(List2, key=sort_fun)
于 2016-01-20T00:44:57.973 回答
0

(在这种情况下)是否有比简单的正则表达式更容易从字符串中提取数据的方法?

import re

def keygen(sort_list):
    return lambda elem: (
        sort_list.index(re.findall(r'^[a-zA-Z]+', elem)[0]),
        re.findall(r'\d+$', elem)
    )

用法:

   SortList = ['ID', 'Name', 'Size', 'Color']
   List1 = ['Name1', 'Name3', 'Color1', 'Size2', 'Color3', 'Color2','Name2', 'Size1', 'ID']
   List2 = ['ID', 'Color1', 'Color2', 'Size1', 'Size2', 'Name1', 'Name2']
   sorted(List1, key=keygen(SortList))
=> ['ID', 'Name1', 'Name2', 'Name3', 'Size1', 'Size2', 'Color1', 'Color2', 'Color3']
   sorted(List2, key=keygen(SortList))
=> ['ID', 'Name1', 'Name2', 'Size1', 'Size2', 'Color1', 'Color2']

解释:

^[a-zA-Z]+匹配开头的字母部分,以及\d$字符串末尾的 - 数字部分。

keygen返回lambda接受一个字符串并返回两项元组:
第一项是列表中字母部分的位置(list = 中没有此类项ValueError),
第二项是最后包含数字部分的单项列表,如果是字符串则为空列表不以数字结尾。

一些可能的改进:

  • sort_list.indexcall is O(n),它将为列表中的每个元素调用;可以用O(1)dict 查找代替以加快排序(我没有这样做以保持简单),
  • 数字部分可以转换为实际整数 ( 1 < 2 < 10, but '1' < '10' < '2')

应用这些后:

import re

def keygen(sort_list):
    index = {(word, index) for index, word in enumerate(sort_slist)}
    return lambda elem: (
        index[re.findall(r'^[a-zA-Z]+', elem)[0]],
        [int(s) for s in re.findall(r'\d+$', elem)]
    )
于 2016-01-19T21:38:19.497 回答