英文:
A short expression to pick from two values based on bool?
问题
如果一个列表中有两个值:
choices = [1,2]
而且想要根据一个名为 `ascending` 的 `bool` 参数将这些值分配给两个变量,可以这样做:
if ascending:
a, b = choices[1], choices[0]
else:
a, b = choices[0], choices[1]
可以使用以下一行代码来表达:
a, b = choices[ascending], choices[not ascending]
或者
a, b = choices[::(-1)**ascending]
我更喜欢最后一种方法,但它可能不够清晰。还有其他更简洁但更可读的方式来实现相同的效果吗?
英文:
If one has two values in a list:
choices = [1,2]
and one wants to assign these values to two variables based on a bool
parameter (let's call it ascending
) like this:
if ascending:
a,b = choices[1], choices[0]
else:
a,b = choices[0], choices[1]
one can express this in one line like this:
a,b = choices[ascending], choices[not ascending]
or
a,b = choices[::(-1)**ascending]
I like the last one better, but it's probably not extremely transparent. What are other concise but more readable ways to do the same?
答案1
得分: 2
如果原始值始终按升序排列,也许这更能表达您的意图:
a, b = sorted(choices, reverse=ascending)
否则,更简单通常更好(参见Kelly的回答),但我可以想出一种方法使它更加晦涩:
例如:
a, b = (iter, reversed)[ascending](choices)
或者,如果其中一种选项比另一种更有可能,您可以基于那个选项进行赋值,如果是另一种情况,则交换变量:
a, b = choices
if ascending: a, b = b, a
英文:
If the original values are always in ascending order, perhaps this would be more expressive of your intent:
a,b = sorted(choices, reverse=ascending)
Otherwise simpler is generally better (see Kelly's answer) but I could think of ways to make it even more obscure:
For example:
a,b = (iter,reversed)[ascending](choices)
Alternatively, if one option is more likely than the other you could do the assignment based on that one and swap the variables if it's the other case:
a,b = choices
if ascending: a,b = b,a
答案2
得分: 1
以下是代码部分的中文翻译:
from timeit import timeit
from statistics import mean, stdev
codes = '''
if ascending:
a, b = choices[1], choices[0]
else:
a, b = choices[0], choices[1]
a, b = choices[ascending], choices[not ascending]
a, b = choices[::(-1)**ascending]
b, a = choices[::ascending or -1]
a, b = choices[::-1 if ascending else 1]
if ascending:
b, a = choices
else:
a, b = choices
a, b = choices[::-ascending or 1]
a, b = choices[::-1] if ascending else choices
a, b = reversed(choices) if ascending else choices
'''.strip().split('\n\n')
choices = ['foo', 'bar']
for ascending in False, True:
print(f'{ascending=}')
for code in codes:
a = b = None
exec(code)
print(a, b)
print()
times = {c: ([], []) for c in codes}
def stats(c):
false, true = (
(mean(ts), stdev(ts))
for ts in times[c]
for ts in [[t*1e9 for t in sorted(ts)[:5]]]
)
return false[0] + true[0], false, true
for _ in range(25):
for ascending in False, True:
setup = f"choices = ['foo', 'bar']; {ascending = }"
for c in codes:
number = 10**5
t = timeit(c, setup, number=number) / number
times[c][ascending].append(t)
print('asc = False asc = True')
for c in sorted(codes, key=stats):
_, false, true = stats(c)
# print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), ' '.join(c.split()))
print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), c.strip().replace('\n', '\n' + ' '*30))
注意:这是代码的中文翻译,不包括代码的执行结果。
英文:
Some ways...
b,a = choices[::ascending or -1]
a,b = choices[::-ascending or 1]
a,b = choices[::-1] if ascending else choices
a,b = choices.pop(ascending), *choices
The last one modifies the list.
Or with multiple lines but kinda clean and I suspect fastest:
if ascending:
b,a = choices
else:
a,b = choices
Benchmarks (times in nanoseconds):
asc = False asc = True
------------ ------------
30.2 ± 0.3 30.2 ± 0.3 if ascending:
b,a = choices
else:
a,b = choices
60.2 ± 1.3 60.8 ± 2.1 a,b = choices[ascending], choices[not ascending]
62.8 ± 0.6 63.5 ± 0.9 if ascending:
a,b = choices[1], choices[0]
else:
a,b = choices[0], choices[1]
30.3 ± 0.3 125.0 ± 3.7 a,b = choices[::-1] if ascending else choices
30.1 ± 0.1 178.2 ± 4.5 a,b = reversed(choices) if ascending else choices
124.5 ± 3.5 126.1 ± 5.8 b,a = choices[::ascending or -1]
133.6 ± 7.0 123.8 ± 2.6 a,b = choices[::-1 if ascending else 1]
143.4 ± 6.4 139.9 ± 6.1 a,b = choices[::-ascending or 1]
169.4 ± 18.5 441.2 ± 20.4 a,b = choices[::(-1)**ascending]
Code (Attempt This Online!):
from timeit import timeit
from statistics import mean, stdev
codes = '''
if ascending:
a,b = choices[1], choices[0]
else:
a,b = choices[0], choices[1]
a,b = choices[ascending], choices[not ascending]
a,b = choices[::(-1)**ascending]
b,a = choices[::ascending or -1]
a,b = choices[::-1 if ascending else 1]
if ascending:
b,a = choices
else:
a,b = choices
a,b = choices[::-ascending or 1]
a,b = choices[::-1] if ascending else choices
a,b = reversed(choices) if ascending else choices
'''.strip().split('\n\n')
choices = ['foo', 'bar']
for ascending in False, True:
print(f'{ascending=}')
for code in codes:
a = b = None
exec(code)
print(a, b)
print()
times = {c: ([], []) for c in codes}
def stats(c):
false, true = (
(mean(ts), stdev(ts))
for ts in times[c]
for ts in [[t*1e9 for t in sorted(ts)[:5]]]
)
return false[0] + true[0], false, true
for _ in range(25):
for ascending in False, True:
setup = f"choices = ['foo', 'bar']; {ascending = }"
for c in codes:
number = 10**5
t = timeit(c, setup, number=number) / number
times[c][ascending].append(t)
print('asc = False asc = True')
for c in sorted(codes, key=stats):
_, false, true = stats(c)
# print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), ' '.join(c.split()))
print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), c.strip().replace('\n', '\n' + ' '*30))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论