[英]Sorting iterables based on preferred order of strings
假設我有一個這樣的列表/元組:
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)在頂部[4]
元素中匹配MyLocation字符串'DE'
元組
這是一個中間步驟, 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
我對如何進行第二種排序感到特別困惑。 請提供代碼樣本以進行第二次排序。
這就夠了:
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')]
您只需通過一次,即可使用特殊的按鍵功能。
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)
鍵函數返回一個值,該值將用於比較列表中的元素。 這個返回一個由兩個元素組成的元組,並且元組根據最早的不同元素進行比較。 所以(1, 0) < (2, -300)
因為1 <2
第一個值是列表['PRF1', 'PRF2', 'PRF3']
中t[3]
的索引;如果不是其中的任何一個,則為數字3。 這意味着它在列表中越早,值越低,並且排序結果越早。 第二個值已在注釋中說明。 :)
總體思路是給每個項目打分。 如果每個項目都有多個分數,則可以將其放入元組。
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)
),但另一方面,可以輕松地以這種方式擴展它。
這有點棘手,但應該這樣做。
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
按其編號排序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.