假设我有一个已存在的数组,如下所示:
x = rand(4)
然后我想将x
重置为零。我能避免执行x = zeros(4)
吗?我担心内存分配。
用一行代码实现的最佳方式是:
x .= zero(y)
或者fill!(x, zero(y))
其中y
是你想要的数字类型。这种方法之所以好用是因为它适用于各种情况。如果x
是任何类型,只要y
与该类型匹配(实际上,你可以使用y = x[1]
),就可以使用此方法。
当我说任何类型时,我的意思是这也适用于奇怪的数字类型,比如SIUnits。如果你使用这个命令,一个包可以支持SIUnits而无需导入该包,因为它会将正确的单位应用于x
值(只要所有操作都在单位上正确),而fill!(x, 0.0)
会由于单位错误而出错(你也可以使用fill!(x, zeros(y))
)。否则,你需要检查单位和其他各种事情。
fill!(x, 0.0)
这将用零覆盖内容。
这应该与仅使用for
循环一样有效:
for i in 1:length(x)
x[i] = 0.0
end
实际上,如果你执行@edit fill!(x, 0.0)
,你会发现这基本上就是它所做的(除了它使用@inbounds
来提高效率)。
我觉得有些人提出了不错的替代方法,但没有人回答实际问题,“什么是最有效的方式(具体来说是指内存方面)”。
所以,这里就是答案。假设:
f1(x) = x = zeros(size(x));
f2(x) = x[:] = zero(x[1]);
f3(x) = fill!(x, zero(x[1]));
f4(x) = x = zero(x);
我们有:
julia> x=rand(1000,1000); @time (for i in 1_000_000_000; x=f1(x); end;)
0.000715 seconds (3 allocations: 7.629 MB)
julia> x=rand(1000,1000); @time (for i in 1_000_000_000; f2(x); end;)
0.000691 seconds (2 allocations: 32 bytes)
julia> x=rand(1000,1000); @time (for i in 1_000_000_000; f3(x); end;)
0.000702 seconds (2 allocations: 32 bytes)
julia> x=rand(1000,1000); @time (for i in 1_000_000_000; x=f4(x); end;)
0.000704 seconds (2 allocations: 7.629 MB)
f1
or f4
are mutating functions; they are not, they return a reference to a new object in memory; i.e. they are there for completeness to demonstrate the bad alternatives that OP is presumably trying to avoid.
I just felt that a question about "efficiency" deserved some numbers to complement the suggestions offered by my colleagues :)
x[:]
和!
都是语法(好吧,!
是约定俗成的),用于原地操作,因此它们不会产生任何临时变量。所以它们相同并不奇怪。x = zero(x)
和x = zeros(length(x))
是返回向量的向量函数,因此它们分配内存也就不足为奇了。我不知道你还想展示什么。 - Chris Rackauckasx[:]
和fill!
不会让人感到惊讶,因为它们没有任何临时变量,因此相同,这是真的,但也不是保证。我们可以尽情探讨理论,但基准测试能消除所有疑虑,不是吗? :) - Tasos Papastylianouf1
和f4
都不会修改函数的参数。它们都创建了一个全新的数组,并恰好将其命名为与函数参数相同的名称。但这只是在函数的本地作用域内更改了名称x
指向的内容,对于调用该函数的数组没有任何影响。 - mbauman
fill!(x, 0.0)
可以自动转换并且似乎可以正常工作。无论如何,fill!(x, zero(eltype(x)))
更加连贯,因为结果必须与x
的元素类型相同,因为它将被放回到同一数组中。 - David P. Sandersfill!(x, 0)
的实现依赖于能够将0转换为正确的类型。在某些情况下,这是不可能的。例如,您无法将0(无量纲)转换为0米
。另一个例子是RGB
值的向量,其中将标量转换为 RGB 值是不明确的。 - tholyx .= 0
。请注意,这三种方法实际上都在底层调用fill!
函数。 - SGJ