[英]Generate list of numbers and their negative counterparts in Python
在 Python 中是否有一个方便的单行生成数字列表及其负对应项?
例如,假设我想生成一个包含数字 6 到 9 和 -6 到 -9 的列表。
我目前的做法是:
l = [x for x in range(6,10)]
l += [-x for x in l]
一个简单的“单线”将是:
l = [x for x in range(6,10)] + [y for y in range(-9, -5)]
但是,生成两个列表然后将它们连接在一起似乎很不方便。
我不确定顺序是否重要,但您可以创建一个元组并将其解压缩到列表理解中。
nums = [y for x in range(6,10) for y in (x,-x)]
print(nums)
[6, -6, 7, -7, 8, -8, 9, -9]
创建一个漂亮且可读的 function:
def range_with_negatives(start, end):
for x in range(start, end):
yield x
yield -x
用法:
list(range_with_negatives(6, 10))
这就是您如何为任何事情获得方便的单线。 避免试图看起来像一个神奇的职业黑客。
我想说最简单的解决方案是使用*
解包运算符将两个范围解包到一个列表中:
>>> [*range(6, 10), *range(-9, -5)]
[6, 7, 8, 9, -9, -8, -7, -6]
这不仅是迄今为止提出的最短答案,而且也是性能最高的,因为它只构造一个列表,并且不涉及超出两个range
的 function 调用。
我通过使用timeit
模块测试所有这个问题的答案来验证这一点:
Answer ID Method timeit result -------------------------------------------------------------------------------------------------- (in question) [x for x in range(6,10)] + [y for y in range(-9, -5)] 0.843 usec per loop (this answer) [*range(6, 10), *range(-9, -5)] 0.509 usec per loop 61348876 [y for x in range(6,10) for y in (x,-x)] 0.754 usec per loop 61349149 list(range_with_negatives(6, 10)) 0.795 usec per loop 61348914 list(itertools.chain(range(6, 10), range(-9, -5))) 0.709 usec per loop 61366995 [sign*x for sign, x in itertools.product((-1, 1), range(6, 10))] 0.899 usec per loop 61371302 list(range(6, 10)) + list(range(-9, -5)) 0.729 usec per loop 61367180 list(range_with_negs(6, 10)) 1.95 usec per loop
(在我自己的电脑上使用 Python 3.6.9 进行时间测试(平均规格))
您可以使用itertools.chain()
连接两个范围。
import itertools
list(itertools.chain(range(6, 10), range(-9, -5)))
您可以使用itertools.product
,它是笛卡尔积。
[sign*x for sign, x in product((-1, 1), range(6, 10))]
[-6, -7, -8, -9, 6, 7, 8, 9]
这可能会更慢,因为您使用乘法,但应该易于阅读。
如果你想要一个纯函数式的解决方案,你也可以导入itertools.starmap
和operator.mul
:
from itertools import product, starmap
from operator import mul
list(starmap(mul, product((-1, 1), range(6, 10))))
但是,这不太可读。
你真的很接近,结合了两个range
对象。 但有一种更简单的方法可以做到这一点:
>>> list(range(6, 10)) + list(range(-9, -5))
[6, 7, 8, 9, -9, -8, -7, -6]
即将每个range
object 转换为一个列表,然后将两个列表连接起来。
另一种方法,使用 itertools:
>>> list(itertools.chain(range(6, 10), range(-9, -5)))
[6, 7, 8, 9, -9, -8, -7, -6]
itertools.chain()
就像一个通用的+
:它不是添加两个列表,而是将一个迭代器一个接一个地链接起来,形成一个“超级迭代器”。 然后将它传递给list()
,你会得到一个具体的列表,在 memory 中包含你想要的所有数字。
IMO 在其他几个答案中提出的使用itertools.chain
的方法绝对是迄今为止提供的最干净的方法。
但是,由于在您的情况下值的顺序无关紧要,因此您可以避免必须定义两个显式range
对象,从而避免使用itertools.chain.from_iterable
执行负range
索引所需的所有非一数学itertools.chain.from_iterable
:
>>> import itertools
>>> list(itertools.chain.from_iterable((x, -x) for x in range(6, 10)))
[6, -6, 7, -7, 8, -8, 9, -9]
有点冗长,但足够可读。
另一个类似的选择是使用带有普通chain
的元组/参数解包:
>>> list(itertools.chain(*((x, -x) for x in range(6, 10))))
[6, -6, 7, -7, 8, -8, 9, -9]
更简洁,但我发现在快速扫描中更难理解元组解包。
权衡另一种可能性。
如果你想要可读性,你原来的单行是相当不错的,但我会将范围更改为相同,因为我认为负边界会使事情变得不那么清晰。
[x for x in range(6, 10)] + [-x for x in range(6, 10)]
这是一个主题的变体(参见@Derte Trdelnik的回答),遵循itertools
的哲学,其中
迭代器构建块 [...] 可单独使用或组合使用。
这个想法是,当我们定义一个新的 function 时,我们不妨让它通用:
def interleaved_negatives(it):
for i in it:
yield i
yield -i
并将其应用于特定的range
迭代器:
list(interleaved_negatives(range(6, 10)))
可以有不同的方法来完成工作。
给定变量: 1. start=6 2. stop=10
def mirror_numbers(start,stop):
if start<stop:
val=range(start,stop)
return [j if i < len(val) else -j for i,j in enumerate([x for x in val]*2) ]
mirror_numbers(6,10)
使用迭代工具:
>>> list(itertools.chain(range(6, 10), range(-9, -5)))
[6, 7, 8, 9, -9, -8, -7, -6]
itertools.chain()
就像一个通用的+
:它不是添加两个列表,而是将一个迭代器一个接一个地链接起来,形成一个“超级迭代器”。 然后将它传递给list()
,你会得到一个具体的列表,在 memory 中包含你想要的所有数字。
如果你想保持你指定的顺序,你可以使用 Python 的内置范围生成器和条件:
def range_with_negs(start, stop):
for value in range(-(stop-1), stop):
if (value <= -start) or (value >= start):
yield value
这给了你 output:
In [1]: list(range_with_negs(6, 10))
Out[1]: [-9, -8, -7, -6, 6, 7, 8, 9]
并且还可以使用 0 作为整个范围的开始。
我喜欢对称。
a = 6
b = 10
nums = [x+y for x in (-(a+b-1),0) for y in range(a,b)]
结果是[-9, -8, -7, -6, 6, 7, 8, 9]
。
我相信 nums 表达式可以改进,“in”和“range”后面的内容在我看来仍然不平衡。
似乎只有两个答案真正给出了一条线,所以这是另一个:
[i for l in map(lambda x: (x, -x), range(6, 10)) for i in l]
[6, -6, 7, -7, 8, -8, 9, -9]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.