Python是否對具有多個鍵的陣列進行排序,是否執行第二個鍵?(它確實執行第二個鍵)如果是這樣,有沒有辦法阻止它在不需要時評估第二個鍵?有沒有一個模塊可以輕松地做到這一點而無需添加額外的代碼?
import random
import itertools
alist=[random.randint(0,10000000) for i in range(10000)]
def cheap(x):
return x%100000
def expensive(x):
def primes():
D = {}
yield 2
for q in itertools.count(3, 2):
p = D.pop(q, None)
if p is None:
yield q
D[q*q] = q
else:
x = p q
while x in D or x % 2 == 0:
x = p
D[x] = p
def nth_prime(n):
if n < 1:
raise ValueError("n must be >= 1 for nth_prime")
for i, p in enumerate(primes(), 1):
if i == n:
return p
return nth_prime(x%99999 1)
alist.sort(key=lambda x: (cheap(x),expensive(x)))
print(alist)
uj5u.com熱心網友回復:
正如您所注意到的,將expensive呼叫放在作為排序lambda函式傳遞的key函式中會急切地呼叫每個值的昂貴計算。如果不希望這樣做,您可能需要撰寫自己的物件以由 key 函式回傳,該函式會在需要時懶惰地計算值。大多數值不需要expensive鍵值,因為它們的cheap值是唯一的。只要您快取每次呼叫的結果,性能就不會受到太大影響(可能比expensive多次運行計算要少得多)。
這就是我的做法。請注意,頂級介面是類工廠函式。
def lazy_keys(*keyfuncs):
class LazyKeyList:
def __init__(self, value):
self.value = value
self.cache = {} # maps from keyfunc to keyfunc(value)
def __iter__(self): # lazily produces values as needed
for keyfunc in keyfuncs:
if keyfunc not in self.cache:
self.cache[keyfunc] = keyfunc(self.value)
yield self.cache[keyfunc]
def __eq__(self, other):
for x, y in zip(self, other):
if x != y:
return False
return True
def __lt__(self, other):
for x, y in zip(self, other):
if x < y:
return True
if x > y:
return False
return False
return LazyKeyList
現在你的排序是:
alist.sort(key=lazy_keys(cheap, expensive))
print(alist)
這是一個更小更簡單的快速和慢速鍵函式示例,它表明它只在必要時運行較慢的函式,對于具有匹配fast鍵結果的值:
from time import sleep
def fast(value):
return value % 10
def slow(value):
print("slow", value)
sleep(1)
return value
x = [random.randrange(20) for _ in range(20)]
print(x)
print(sorted(x, key=lazy_keys(fast, slow)))
輸出是:
[6, 3, 7, 3, 2, 11, 6, 8, 15, 10, 12, 16, 2, 7, 19, 4, 5, 7, 2, 17]
slow 3
slow 3
slow 6
slow 6
slow 12
slow 2
slow 16
slow 2
slow 7
slow 7
slow 5
slow 15
slow 7
slow 2
slow 17
[10, 11, 2, 2, 2, 12, 3, 3, 4, 5, 15, 6, 6, 16, 7, 7, 7, 17, 8, 19]
uj5u.com熱心網友回復:
它確實運行第二個函式,解決這個問題的一種方法是按第一個鍵對其進行排序,然后是第二個
values = set(map(lambda x:x[1], alist)) newlist = [[y[0] for y in alist if y[1]==x] for x in values]
呃,IDK過了這一點。我真的只是想打開一個討論,
uj5u.com熱心網友回復:
您可以按 排序和分組cheap,然后按以下方式對包含多個元素的每組進行排序expensive:
alist.sort(key=cheap)
result = []
for _, [*g] in itertools.groupby(alist, cheap):
if len(g) > 1:
g.sort(key=expensive)
result = g
print(result)
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/480045.html
