根据首选的字符串顺序对迭代进行排序

时间:2011-04-13 17:45:55

标签: python sorting

假设我有一个像这样的列表/元组:

MyLocation = 'DE'
(    
('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),
('Pencils', '', 19.95, 'PVT', 'IT'),
('Pencils', '', 23.50, 'PRF1', 'US'),
('Pencils', 'Wooden Pencils', 23.50, 'PRF2', 'DE'),
('Pencils', '', 12.50, 'NON', 'DE'))   

我希望按照以下规则分两次进行排序:

1)匹配'DE'元素中MyLocation字符串[4]的元组,位于顶部
这是一个中间步骤,DE之间的相对顺序无关紧要。这样所有DE都位于顶部。

(    
('Pencils', '', 12.50, 'NON', 'DE'),
('Pencils', 'Wooden Pencils', 23.50, 'PRF2', 'DE'),
('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),    
('Pencils', '', 23.50, 'PRF1', 'US'),
('Pencils', '', 19.95, 'PVT', 'IT')       
)  

2)之后,对[3] rd元素进行排序,首选顺序应为['PRF1', 'PRF2', 'PRF3']。其他字符串可以留在较低的位置。

我预期的最终排序输出是

(    
('Pencils', '', 23.50, 'PRF1', 'US'),
('Pencils', 'Wooden Pencils', 23.50, 'PRF2', 'DE'),
('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),    
('Pencils', '', 12.50, 'NON', 'DE'),
('Pencils', '', 19.95, 'PVT', 'IT')       
)  

我怎么去这两种?我可以用del和insert来管理第一个排序,但建议的方法是什么?

tempList = actualList
i = 0
for record in actualList:
    if record[5] == 'DE':
        del tempList[i]
        tempList.insert(0, record)
    i = i + 1
actualList = tempList

我对如何进行第二次排序感到特别困惑。请提供第二次排序的代码示例。

4 个答案:

答案 0 :(得分:2)

这就够了:

PRF = ('PRF1', 'PRF2', 'PRF3')
sorted(records, key=lambda x:(x[4]!='DE', PRF.index(x[3]) if x[3] in PRF else 3))

或者如果你要使用它,那么一旦你想分开关键功能:

k = lambda x: (x[4]!='DE', PRF.index(x[3]) if x[3] in PRF else len(PRF))

然后只需使用

sorted(records, key=k)
在你的例子中

>>> records = ( ('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),
... ('Pencils', '', 19.95, 'PVT', 'IT'),
... ('Pencils', '', 23.50, 'PRF1', 'US'),
... ('Pencils', 'Wooden Pencils', 23.50, 'PRF2', 'DE'),
... ('Pencils', '', 12.50, 'NON', 'DE') )
>>> import pprint
>>> pprint.pprint(sorted(records, key=k))
[('Pencils', 'Wooden Pencils', 23.5, 'PRF2', 'DE'),
 ('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),
 ('Pencils', '', 12.5, 'NON', 'DE'),
 ('Pencils', '', 23.5, 'PRF1', 'US'),
 ('Pencils', '', 19.95, 'PVT', 'IT')]

答案 1 :(得分:1)

您只需要一次通过,具有特殊的按键功能。

def key(t):
    return (
        dict(PRF1=0, PRF2=1, PRF3=2).get(t[3], 3), # earlier ones get smaller numbers
        int(t[4] != 'DE')) # 0 if DE, 1 otherwise

L.sort(key=key)

key函数返回一个值,用于比较列表中的元素。这个返回一个由两个元素组成的元组,元组根据最早的不同元素进行比较。所以(1, 0) < (2, -300)因为1&lt; 2。

第一个值是列表t[3]中的['PRF1', 'PRF2', 'PRF3']索引或第3个值(如果不是这些索引)。这意味着列表中较早的值,值越低,排序结果中越早。第二个值已在注释中说明。 :)

答案 2 :(得分:1)

一般的想法是给每个项目一个分数。如果每个项目有多个分数,则可以将其放入元组中。

MyLocation = 'DE'
location_score = { MyLocation : 1 }
that_other_field_score = {'PRF1' : 3, 'PRF2' : 2, 'PRF3' : 1}

def score( row ):
    # returns a tuple of item score
    # items not in the score dicts get score 0 for that field
    return ( that_other_field_score.get(row[3], 0),
                  location_score.get(row[4], 0))    

data = [    
('Pencils', 'Artists Pencils', 18.95, 'PVT', 'DE'),
('Pencils', '', 19.95, 'PVT', 'IT'),
('Pencils', '', 23.50, 'PRF1', 'US'),
('Pencils', 'Wooden Pencils', 23.50, 'PRF2', 'DE'),
('Pencils', '', 12.50, 'NON', 'DE')]

# sort data, highest score first
data.sort(key=score, reverse=True)
print data 

location_score dict可能有点矫枉过正(你可以写(1 if row[4]=='DE' else 0))但另一方面它可以通过这种方式轻松扩展。

答案 3 :(得分:0)

这有点苛刻,但应该这样做。

def prf_key(item):
    if item[3][:3] == 'PRF':
        return (0, int(item[3:]))
    else:
        return (1, None)

actualList.sort(key = prf_key)

我们的想法是,任何PRF都应该排在最前面,因此它会返回一个以0开头的元组,其余为1;然后PRF按照他们的号码排序。