填充数组的最快方法是什么?

3
我想要填充一个大小为n的数组,就像这个(非常大的)数组:
1 for i = 1, (n/2)+1

2 for i = 2, 3, ... , (n/2)

0 for i = (n/2)+2, ... , n

在0到n之间迭代并对每个数字使用if语句和%是最快的方法吗?

像这样:

array = []
for index in range(1,n):
    if index == 1 or (index % ((n/2)+1) == 0):
        array.append(1)
    if index == 2 or index == 3 or (index % (n/2) == 0):
        array.append(2)
    if (index % ((n/2)+2) == 0):
        array.append(0)

我曾尝试想出其他方法来实现这个需求,但是一直没有头绪。虽然我不是专业程序员,但我也不知道还有什么其他的实现方式。


这些都不会起作用。你不能通过分配索引来创建列表元素,必须使用array.append() - Barmar
一般来说,循环设置每个项目并不是最快的方法。但首先需要澄清几件事情:(1)u是什么?(2)你如何处理奇数n? - Jake Stevens-Haas
顺便提一下,[] 创建的是列表,而不是数组。Python 只有在像 numpy 这样的模块中才有数组。 - Barmar
i = 0 时,该值应该是多少? - Barmar
但是你的文本说从0到n,而不是从1到n。这个问题真的很令人困惑,你确定你理解了要求吗?也许你应该展示一个实际的期望结果的例子。 - Barmar
显示剩余4条评论
4个回答

1
你可能想要使用numpy来实现这一点。您可以使用np.r_将多个切片连接起来,并将它们用于对数组进行切片分配:
import numpy as np

n = 10
a = np.zeros(n)
a[np.r_[0,n//2]] = 1
a[np.r_[1:n//2]] = 2
a[np.r_[n//2+1:n]] = 0

print(a)
array([1., 2., 2., 2., 2., 1., 0., 0., 0., 0.])

第一个元素不应该是 0 吗? - Barmar
不,我认为OP的“1”是起始位置(0)@bramar - yatu
它应该是 [0, 1, 2, 2, 2, 0, 0, 0, 0, 0] - Barmar
@Barmar,yatu:规格没有定义第一个元素,因为它是从零开始的,如果是从一开始的话,第一个元素就是1。 - Willem Van Onsem
@WillemVanOnsem 是的,我假设第一个元素是1,也因为最后一个元素是n,而不是n-1。 - yatu

1

由于其他答案使用了相当快速的numpy数组,为了完整性,我想补充一些其他的答案。(显然原问题有一些关于n是奇数时该怎么办以及作者是否期望从零开始或从一开始索引的歧义。)

你可以使用列表推导式很简单地创建一个列表。

[1 if i in [0, n/2] else (2 if i <=(n/2) else 0) for i in range(0, n)]

但更快的方法是通过扩展类来扩展列表的功能:

class NewThing(list):
    def __init__(self, n):
        self.n = n
    def __getitem__(self,i):
        if i in {0,n/2}:
            return 1
        elif i <=n/2:
            return 2
        return 0
    def to_list(self):
        return [self[i] for i in range(0, n)]

>>>unique_list = NewThing(len(u))
>>>unique_list[4]
2
>>>unique_list.to_list()
[1, 2, 2, 2, 2, 1, 0, 0, 0, 0]

你可以调用整个列表,也可以只调用单个元素。创建整个列表仍然很慢。

1
构建这样的集合最有效的方法是使用numpy数组。
我们可以使用以下代码构建:
import numpy as np

def generate_array(n):
    a = np.hstack((np.full(n//2+1, 2), np.zeros(n//2-1)))
    a[[0, n//2]] = 1
    return a

例如:

>>> generate_array(6)
array([1., 2., 2., 1., 0., 0.])
>>> generate_array(10)
array([1., 2., 2., 2., 2., 1., 0., 0., 0., 0.])
>>> generate_array(16)
array([1., 2., 2., 2., 2., 2., 2., 2., 1., 0., 0., 0., 0., 0., 0., 0.])

时间:

n=100_000 时,我们得到:

>>> timeit(partial(generate_array, 100_000), number=10_000)
1.0764452270013862

对于 n=1_000_000,我们得到:

>>> timeit(partial(generate_array, 1_000_000), number=1_000)
6.448311180000019

生成一个包含10万个元素的数组,所需时间约为(包括partial等小开销)107.64 微秒,生成一个包含100万个元素的数组需要6448.31微秒


1

对于所有偶数的n

def generate_array2(n):
    a = np.empty((2,n//2))
    a[0]=2
    a[1]=0
    a[:,0]=1
    return a.ravel()

%timeit a= generate_array2(1_000_000)
491 ± 6.58 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接