一个基于布尔值选择两个值的简短表达式?

huangapple go评论101阅读模式
英文:

A short expression to pick from two values based on bool?

问题

  1. 如果一个列表中有两个值

choices = [1,2]

  1. 而且想要根据一个名为 `ascending` `bool` 参数将这些值分配给两个变量,可以这样做:

if ascending:
a, b = choices[1], choices[0]
else:
a, b = choices[0], choices[1]

  1. 可以使用以下一行代码来表达:

a, b = choices[ascending], choices[not ascending]

  1. 或者

a, b = choices[::(-1)**ascending]

  1. 我更喜欢最后一种方法,但它可能不够清晰。还有其他更简洁但更可读的方式来实现相同的效果吗?
英文:

If one has two values in a list:

  1. 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:

  1. if ascending:
  2. a,b = choices[1], choices[0]
  3. else:
  4. a,b = choices[0], choices[1]

one can express this in one line like this:

  1. a,b = choices[ascending], choices[not ascending]

or

  1. 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

如果原始值始终按升序排列,也许这更能表达您的意图:

  1. a, b = sorted(choices, reverse=ascending)

否则,更简单通常更好(参见Kelly的回答),但我可以想出一种方法使它更加晦涩:

例如:

  1. a, b = (iter, reversed)[ascending](choices)

或者,如果其中一种选项比另一种更有可能,您可以基于那个选项进行赋值,如果是另一种情况,则交换变量:

  1. a, b = choices
  2. if ascending: a, b = b, a
英文:

If the original values are always in ascending order, perhaps this would be more expressive of your intent:

  1. 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:

  1. 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:

  1. a,b = choices
  2. if ascending: a,b = b,a

答案2

得分: 1

以下是代码部分的中文翻译:

  1. from timeit import timeit
  2. from statistics import mean, stdev
  3. codes = '''
  4. if ascending:
  5. a, b = choices[1], choices[0]
  6. else:
  7. a, b = choices[0], choices[1]
  8. a, b = choices[ascending], choices[not ascending]
  9. a, b = choices[::(-1)**ascending]
  10. b, a = choices[::ascending or -1]
  11. a, b = choices[::-1 if ascending else 1]
  12. if ascending:
  13. b, a = choices
  14. else:
  15. a, b = choices
  16. a, b = choices[::-ascending or 1]
  17. a, b = choices[::-1] if ascending else choices
  18. a, b = reversed(choices) if ascending else choices
  19. '''.strip().split('\n\n')
  20. choices = ['foo', 'bar']
  21. for ascending in False, True:
  22. print(f'{ascending=}')
  23. for code in codes:
  24. a = b = None
  25. exec(code)
  26. print(a, b)
  27. print()
  28. times = {c: ([], []) for c in codes}
  29. def stats(c):
  30. false, true = (
  31. (mean(ts), stdev(ts))
  32. for ts in times[c]
  33. for ts in [[t*1e9 for t in sorted(ts)[:5]]]
  34. )
  35. return false[0] + true[0], false, true
  36. for _ in range(25):
  37. for ascending in False, True:
  38. setup = f"choices = ['foo', 'bar']; {ascending = }"
  39. for c in codes:
  40. number = 10**5
  41. t = timeit(c, setup, number=number) / number
  42. times[c][ascending].append(t)
  43. print('asc = False asc = True')
  44. for c in sorted(codes, key=stats):
  45. _, false, true = stats(c)
  46. # print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), ' '.join(c.split()))
  47. print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), c.strip().replace('\n', '\n' + ' '*30))

注意:这是代码的中文翻译,不包括代码的执行结果。

英文:

Some ways...

  1. b,a = choices[::ascending or -1]
  2. a,b = choices[::-ascending or 1]
  3. a,b = choices[::-1] if ascending else choices
  4. a,b = choices.pop(ascending), *choices

The last one modifies the list.

Or with multiple lines but kinda clean and I suspect fastest:

  1. if ascending:
  2. b,a = choices
  3. else:
  4. a,b = choices

Benchmarks (times in nanoseconds):

  1. asc = False asc = True
  2. ------------ ------------
  3. 30.2 ± 0.3 30.2 ± 0.3 if ascending:
  4. b,a = choices
  5. else:
  6. a,b = choices
  7. 60.2 ± 1.3 60.8 ± 2.1 a,b = choices[ascending], choices[not ascending]
  8. 62.8 ± 0.6 63.5 ± 0.9 if ascending:
  9. a,b = choices[1], choices[0]
  10. else:
  11. a,b = choices[0], choices[1]
  12. 30.3 ± 0.3 125.0 ± 3.7 a,b = choices[::-1] if ascending else choices
  13. 30.1 ± 0.1 178.2 ± 4.5 a,b = reversed(choices) if ascending else choices
  14. 124.5 ± 3.5 126.1 ± 5.8 b,a = choices[::ascending or -1]
  15. 133.6 ± 7.0 123.8 ± 2.6 a,b = choices[::-1 if ascending else 1]
  16. 143.4 ± 6.4 139.9 ± 6.1 a,b = choices[::-ascending or 1]
  17. 169.4 ± 18.5 441.2 ± 20.4 a,b = choices[::(-1)**ascending]

Code (Attempt This Online!):

  1. from timeit import timeit
  2. from statistics import mean, stdev
  3. codes = '''
  4. if ascending:
  5. a,b = choices[1], choices[0]
  6. else:
  7. a,b = choices[0], choices[1]
  8. a,b = choices[ascending], choices[not ascending]
  9. a,b = choices[::(-1)**ascending]
  10. b,a = choices[::ascending or -1]
  11. a,b = choices[::-1 if ascending else 1]
  12. if ascending:
  13. b,a = choices
  14. else:
  15. a,b = choices
  16. a,b = choices[::-ascending or 1]
  17. a,b = choices[::-1] if ascending else choices
  18. a,b = reversed(choices) if ascending else choices
  19. '''.strip().split('\n\n')
  20. choices = ['foo', 'bar']
  21. for ascending in False, True:
  22. print(f'{ascending=}')
  23. for code in codes:
  24. a = b = None
  25. exec(code)
  26. print(a, b)
  27. print()
  28. times = {c: ([], []) for c in codes}
  29. def stats(c):
  30. false, true = (
  31. (mean(ts), stdev(ts))
  32. for ts in times[c]
  33. for ts in [[t*1e9 for t in sorted(ts)[:5]]]
  34. )
  35. return false[0] + true[0], false, true
  36. for _ in range(25):
  37. for ascending in False, True:
  38. setup = f"choices = ['foo', 'bar']; {ascending = }"
  39. for c in codes:
  40. number = 10**5
  41. t = timeit(c, setup, number=number) / number
  42. times[c][ascending].append(t)
  43. print('asc = False asc = True')
  44. for c in sorted(codes, key=stats):
  45. _, false, true = stats(c)
  46. # print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), ' '.join(c.split()))
  47. print('{:5.1f} ± {:4.1f} {:5.1f} ± {:4.1f} '.format(*false, *true), c.strip().replace('\n', '\n' + ' '*30))

huangapple
  • 本文由 发表于 2023年4月7日 00:21:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75951678.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定