簡體   English   中英

根據字符串的首選順序對可迭代對象進行排序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM