Julia 是否有一个函数可以让我控制变量arg的数量?
我有以下代码:Julia 是否有一个函数可以让我控制变量arg的数量?,julia,Julia,我有以下代码: circ(x) = x./sqrt(sum(x .* x)) x -> cat(circ(x), circ(x); dims = 1) 但是我希望能够创建一个函数,在这里我输入一个数字,然后它连接这个数字的circ(x) 例如: function Ncircs(n) #some way to make cat() have as its parameter circ n number of times end 我可以打电话给Ncircs(2),然后 x->cat(
circ(x) = x./sqrt(sum(x .* x))
x -> cat(circ(x), circ(x); dims = 1)
但是我希望能够创建一个函数,在这里我输入一个数字,然后它连接这个数字的circ(x)
例如:
function Ncircs(n)
#some way to make cat() have as its parameter circ n number of times
end
我可以打电话给Ncircs(2),然后
x->cat(循环(x),循环(x);dims=1)
或Ncircs(3)
并获取
x->cat(循环(x)、循环(x)、循环(x);dims=1)
或Ncircs(4)
并获取
x->cat(circ(x)、circ(x)、circ(x)、circ(x);dims=1)
等等
有没有办法做到这一点?我必须使用宏吗?您可以编写:
Ncircs(n) = x -> cat(Iterators.repeated(circ(x), n)...; dims = 1)
如果您知道您将始终执行dims=1
,则使用vcat
和reduce
Ncircs(n) = x -> reduce(vcat, Iterators.repeated(circ(x), n))
对于大型n
,效率更高
作为旁注:使用另一个选项(vcat
)将产生类型稳定的结果,而第一个选项不是类型稳定的
编辑
为什么不允许对空集合进行缩减?
一般来说,原因是你无法判断减少的结果。如果要允许空集合,则应添加init
关键字参数。以下是一个例子:
julia> reduce(vcat, [])
ERROR: ArgumentError: reducing over an empty collection is not allowed
julia> reduce(vcat, [], init = [1])
1-element Array{Int64,1}:
1
julia> reduce(vcat, [[2,3], [4,5]], init = [1])
5-element Array{Int64,1}:
1
2
3
4
5
结果是类型稳定的是什么意思
这意味着Julia能够在编译时(在执行代码之前)判断函数返回值的类型。类型稳定的代码通常运行得更快(不过这是一个广泛的主题-我建议您阅读Julia手册以详细了解它)。您可以使用@code\u warntype
和测试来检查函数的类型是否稳定。@extensated
在这里,让我对您的具体案例进行解释(我截断了一些输出以缩短答案)
上面的任何表示编译器不知道答案的类型。原因是在这种情况下,此类型取决于dims
参数。如果它是1
它将是一个向量,如果它是2
它将是一个矩阵
我如何知道它对于大型n
您可以运行@哪个
宏:
julia> @which reduce(vcat, [[1,2,3], [4,5,6]])
reduce(::typeof(vcat), A::AbstractArray{#s72,1} where #s72<:(Union{AbstractArray{T,2}, AbstractArray{T,1}} where T)) in Base at abstractarray.jl:1321
一个编辑器将打开,您会看到它调用了一个内部函数\u-typed\u-vcat
,该函数针对vcat
进行了优化,使用了大量数组。之所以引入此优化,是因为使用类似于vcat([[1,2,3],[4,5,6]])
的splatting在结果上是等效的,但您必须进行splatting(即…
),这本身就有一些成本,可以使用reduce
版本避免
为了确保我所说的是真实的,您可以执行以下基准测试:
julia> using BenchmarkTools
julia> y = [[i] for i in 1:10000];
julia> @benchmark vcat($y...)
BenchmarkTools.Trial:
memory estimate: 156.45 KiB
allocs estimate: 3
--------------
minimum time: 67.200 μs (0.00% GC)
median time: 77.800 μs (0.00% GC)
mean time: 102.804 μs (8.50% GC)
maximum time: 35.179 ms (99.47% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark reduce(vcat, $y)
BenchmarkTools.Trial:
memory estimate: 78.20 KiB
allocs estimate: 2
--------------
minimum time: 67.700 μs (0.00% GC)
median time: 69.700 μs (0.00% GC)
mean time: 82.442 μs (6.39% GC)
maximum time: 32.719 ms (99.58% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark cat($y..., dims=1)
ERROR: StackOverflowError:
您可以看到
reduce
版本的速度略快于vcat
的splatting版本,而cat
对于非常大的n
(对于较小的n
,它可以工作,但速度要慢一些)。谢谢!这是一个了不起的反应!我想知道你是否介意回答几个问题,这样我就可以了解:你怎么知道对大n使用你的建议会更有效?另外,对于类型稳定的结果意味着什么?另外,我想选择性地将n设置为零,但不允许在空集合上减少。我将如何解决这个问题?此外,我回顾了上下文,并意识到如果这有帮助的话,我永远不会真正需要一个非常大的n。我将在答案中添加额外的注释。
@edit reduce(vcat, [[1,2,3], [4,5,6]])
julia> using BenchmarkTools
julia> y = [[i] for i in 1:10000];
julia> @benchmark vcat($y...)
BenchmarkTools.Trial:
memory estimate: 156.45 KiB
allocs estimate: 3
--------------
minimum time: 67.200 μs (0.00% GC)
median time: 77.800 μs (0.00% GC)
mean time: 102.804 μs (8.50% GC)
maximum time: 35.179 ms (99.47% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark reduce(vcat, $y)
BenchmarkTools.Trial:
memory estimate: 78.20 KiB
allocs estimate: 2
--------------
minimum time: 67.700 μs (0.00% GC)
median time: 69.700 μs (0.00% GC)
mean time: 82.442 μs (6.39% GC)
maximum time: 32.719 ms (99.58% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark cat($y..., dims=1)
ERROR: StackOverflowError: