如何根據整數串列的絕對值對整數串列進行排序,以使正數獲得更高的優先級 -
樣本輸入
lst = [1, -3, 3, -3, 12, 10]
預期產出
[1, 3, -3, -3, 10, 12]
我現在可以用這樣的代碼做到這一點,但我0.1對函式中的任意性感到困擾,想知道是否有更清潔的方法
我的代碼
sorted(lst, key=lambda x: abs(x) if x >= 0 else abs(x) 0.1)
# [1, 3, -3, -3, 10, 12]
uj5u.com熱心網友回復:
另一種解決方案是將元組作為排序鍵:
sorted(lst, key=lambda x: (abs(x), x < 0))
為了更好地理解它:
1 ~ (1, False) ~ (1, 0)
-3 ~ (3, True) ~ (3, 1)
3 ~ (3, False) ~ (3, 0)
-3 ~ (3, True) ~ (3, 1)
12 ~ (12, False) ~ (12, 0)
10 ~ (10, False) ~ (10, 0)
uj5u.com熱心網友回復:
通常情況下,兩種簡單的排序在這里可能比使用元組的一種更有效:
lst.sort(reverse=True)
lst.sort(key=abs)
這利用了排序函式的穩定性,因此保留了第一次排序的順序以打破第二次排序中的平局。另請參閱 Python 的Sorting HOW TO關于此技術。
順便說一句,如果沒有不必要的東西,你的會更短更快abs(你已經知道這個標志):
sorted(lst, key=lambda x: x if x >= 0 else 0.5 - x)
此外,排序函式針對所有值都具有相同型別的情況進行了優化,因此如果我們簡單地將 0.0 添加到非負數x以使其也成為 a float,則使用此優化。順便說一句.,在 Jupri 當前已洗掉的答案中添加一個可以修復它,然后它非常整潔且同樣快速。
像你的“幾個 100 個元素長”串列和更長的串列這樣的基準:
500 random integers from -500 to 500
82.9 μs ± 0.2 μs Kelly
113.6 μs ± 0.5 μs original_mod2
117.5 μs ± 0.4 μs Jupri
191.7 μs ± 0.3 μs Yevhen
196.2 μs ± 0.6 μs Ch3ster
215.0 μs ± 0.7 μs original_mod1
233.5 μs ± 0.5 μs original
100,000 random integers from -100,000 to 100,000
39.4 ms ± 0.1 ms Kelly
40.2 ms ± 0.4 ms original_mod2
41.6 ms ± 0.3 ms Jupri
90.2 ms ± 0.5 ms original_mod1
94.9 ms ± 0.4 ms original
115.9 ms ± 2.7 ms Yevhen
131.5 ms ± 2.6 ms Ch3ster
基準代碼(在線試用!):
def original(lst):
return sorted(lst, key=lambda x: abs(x) if x >= 0 else abs(x) 0.1)
def original_mod1(lst):
return sorted(lst, key=lambda x: x if x >= 0 else 0.5-x)
def original_mod2(lst):
return sorted(lst, key=lambda x: x 0.0 if x >= 0 else 0.5-x)
def Kelly(lst):
lst = sorted(lst, reverse=True)
lst.sort(key=abs)
return lst
def Yevhen(lst):
return sorted(lst, key=lambda x: (abs(x), x < 0))
def Ch3ster(lst):
return sorted(lst, key=lambda x: (abs(x), -x))
def Jupri(lst):
return sorted(lst, key=lambda x: abs(x-.1))
funcs = [original, original_mod1, original_mod2, Kelly, Yevhen, Ch3ster, Jupri]
import random
from timeit import default_timer as timer
from statistics import mean, stdev
def test(n, repeats, unit):
print(f'{n:,} random integers from {-n:,} to {n:,}')
times = {func: [] for func in funcs}
def stats(func):
ts = sorted(times[func])[:3]
mn = mean(ts)
sd = stdev(ts)
return f'{mn*1e3:5.1f} ms ± {sd*1e3:3.1f} ms ' if unit == 'ms' else f'{mn*1e6:5.1f} μs ± {sd*1e6:3.1f} μs '
for _ in range(15):
lst = random.choices(range(-n, n 1), k=n)
expect = original(lst)
random.shuffle(funcs)
for func in funcs:
t = 0
for _ in range(repeats):
t0 = timer()
result = func(lst)
t = (timer() - t0) / repeats
assert result == expect
del result
times[func].append(t)
for func in sorted(funcs, key=stats):
print(stats(func), func.__name__)
print()
test(500, 500, 'μs')
test(10**5, 1, 'ms')
uj5u.com熱心網友回復:
創建一個自定義比較器函式,它回傳一個大小為 2 的元組。元組的第一個值用于絕對值,第二個值用于對具有相同絕對值的負值和正值進行排序。
sorted(lst, key=lambda x: (abs(x), -x))
# [1, 3, -3, -3, 10, 12]
對于串列中的每個值,比較的值將是:
1 -> (1, -1)
3 -> (3, -3)
-3 -> (3, 3)
10 -> (10, -10)
12 -> (12, -12)
這樣,在每組中,正值被推到開頭,負值被推到末尾。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/487389.html
