gpt4 book ai didi

julia - 在 Julia 中从范围创建数组而不使用 Collect()

转载 作者:行者123 更新时间:2023-12-01 10:19:27 25 4
gpt4 key购买 nike

在从范围创建数组时,我对 Julia 中的这种行为感到有些困惑。我想知道以下的基 native 制。

A = [1:10]

结果 1-element Array{UnitRange{Int64},1}
这不是我想要的。上面的代码创建了一个数组 UnitRange . Julia 文档推荐使用 collect()从范围创建数组如下:
A = collect(1:10)

结果 10-element Array{Int64,1} .完美的。

但是,如果我在范围后添加分号,此代码也有效。
A = [1:10;]

根据 Julia 文档, ;vcat() 的简写或垂直串联。 vcat有什么意义将其用作 A = [1:10;] 时.它不仅看起来很奇怪(它用什么 vcat'ing ?),对我来说也没有意义。

我想清楚地解释一下范围如何与 vcat 交互。

最佳答案

range 是从不分配的“懒惰”向量。它可能是最有用的迭代器之一。

julia> AbstractRange <: AbstractVector
true

julia> @allocated [1,2,3,4,5,6,7,8,9,10]
160

julia> @allocated 1:10
0

范围运算符 : 用于创建范围:
julia> 1:10 |> dump
UnitRange{Int64}
start: Int64 1
stop: Int64 10

您已经知道如何使用 collect 将范围转换为向量,但是如果您能更深入地研究代码,您会发现 collect 实际上在幕后调用 vcat :
julia> @less collect(1:10)

collect(r::AbstractRange) = vcat(r)

这就是 vcat 处理 AbstractRange 输入的方式:
@less vcat(1:10)    

function vcat(rs::AbstractRange{T}...) where T
n::Int = 0
for ra in rs
n += length(ra)
end
a = Vector{T}(undef, n)
i = 1
for ra in rs, x in ra
@inbounds a[i] = x
i += 1
end
return a
end

实现非常简单,只需循环输入(注意 rs 是可变参数输入),并将输入范围一一连接到单个向量中。显然,即使只有一个输入范围,它也能工作,这就是 [1:10;] 的情况。

还有另一种从范围创建向量的方法:直接调用 Vector 构造函数 Vector(1:10) 。但是引擎盖下会发生什么?简单地调用 @less Vector(1:10) 不会直接跳转到原始实现,这就是花哨的调试器的用武之地:
julia> using Debugger

julia> @enter Vector(1:10)
In Type(x) at boot.jl:424
>424 (::Type{Array{T,N} where T})(x::AbstractArray{S,N}) where {S,N} = Array{S,N}(x)

About to run: (Core.apply_type)(Array, Int64, 1)
1|debug> s
In Type(x) at boot.jl:424
>424 (::Type{Array{T,N} where T})(x::AbstractArray{S,N}) where {S,N} = Array{S,N}(x)

About to run: (Array{Int64,1})(1:10)
1|debug> s
[ Info: tracking Base
In Type(r) at range.jl:943
>943 Array{T,1}(r::AbstractRange{T}) where {T} = vcat(r)

About to run: (vcat)(1:10)
1|debug> s
In vcat(rs) at range.jl:930
>930 n::Int = 0
931 for ra in rs
932 n += length(ra)
933 end
934 a = Vector{T}(undef, n)

About to run: Core.NewvarNode(:(_5))

如您所见, Vector 也调用 vcat

我认为这个例子已经给了你一些关于如何使用这些非常方便的内置反射工具在 Julia REPL 中交互式地找到答案的想法。还有其他有用的工具,如 @code_lowered@code_typed@macroexpand 等,可以帮助您找出诸如“这个表达式有什么作用?”之类的问题,例如,
julia> f() = [1:10;]
f (generic function with 1 method)

julia> @code_lowered f()
CodeInfo(
1 ─ %1 = 1:10
│ %2 = (Base.vcat)(%1)
└── return %2
)

“降低”的代码告诉我们 Julia 首先创建一个范围 %1 = 1:10 ,然后调用 Base.vcat(%1) ,这正是文档所说的。

X-ref: What is the difference between @code_native, @code_typed and @code_llvm in Julia?

关于julia - 在 Julia 中从范围创建数组而不使用 Collect(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55438134/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com