对具有更高优先级正数的绝对值的整数列表进行排序
Sort a list of integers on absolute values with higher precedence positive number
如何根据整数的绝对值对整数列表进行排序,以便正数获得更高的优先级 -
样本输入
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]
另一种解决方案是使用元组作为排序键:
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)
创建一个自定义比较器函数,其中 returns 一个大小为 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)
这样正值被推到每个组的开头,负值被推到结尾。
通常情况下,两种简单排序在这里可能比一种使用元组的排序更有效:
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 添加到 non-negative x
使其也成为 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
基准代码(Try it online!):
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')
如何根据整数的绝对值对整数列表进行排序,以便正数获得更高的优先级 -
样本输入
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]
另一种解决方案是使用元组作为排序键:
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)
创建一个自定义比较器函数,其中 returns 一个大小为 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)
这样正值被推到每个组的开头,负值被推到结尾。
通常情况下,两种简单排序在这里可能比一种使用元组的排序更有效:
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 添加到 non-negative x
使其也成为 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
基准代码(Try it online!):
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')