在Julia中访问结构数组中字段的最佳方法

Ada*_*ler 5 julia

struct Point
   x :: Int
   y :: Int
end
Run Code Online (Sandbox Code Playgroud)

如果我有一个atype 数组Array{Point},是否有比这更好的方法(在语法上更干净或更快速)进行字段访问?

(p->p.x).(a)
Run Code Online (Sandbox Code Playgroud)

Col*_*ers 5

四个选项是:

1) (p->p.x).(a)

2) [ z.x for z in a ]

3) map(p->p.x, a)

4)getfield.(a, x)(迈克尔在评论中建议)

前 3 种方法的效率差不多,所以这取决于个人喜好。方法 4 在我的机器上有点慢,但正如其他回答者 (Gnimuc) 所说,这有望通过问题 #22710 解决。

请注意,我也经常发现以下方法很有用:

getx(a::Vector{Point}, inds=1:length(a))::Vector{Int} = [ a[i].x for i in inds ]
Run Code Online (Sandbox Code Playgroud)

它允许您x为任意一组输入索引提取字段。(虽然拉出每个索引会比上面3种方法稍微慢一些)。我的元编程很烂,但你实际上可以做这样的事情:

for fn in fieldnames(Point)
    eval(parse("get$(fn)(a::Vector{Point}, inds=1:length(a))::Vector{Int} = [ a[i].$(fn) for i in inds ]"))
end
Run Code Online (Sandbox Code Playgroud)

这将为您提供上述getx功能,但对于输入类型中的每个字段名...

  • 或者`getfield.(a,x)` (3认同)

Gni*_*muc 5

简洁的方法是定义您自己的运算符,该运算符最初由@pabloferz在 Discourse 上发布:https : //discourse.julialang.org/t/broadcast-over-getfield-in-0-6/2335/4

struct Point
   x :: Int
   y :: Int
end

a = [Point(i,j) for i = 1:10 for j = 1:10]

?(val, s) = getfield(val, s)
a .? :x
a .? :y
Run Code Online (Sandbox Code Playgroud)

更新:

目前,(p->p.x).(a)如果a较小,快速基准测试显示是其他解决方案中最快的。当 的长度a变大时,mapcomprehension都比 略快(p->p.x).(a)

julia> versioninfo()
Julia Version 0.6.0
Commit 903644385b* (2017-06-19 13:05 UTC)
......

julia> @btime (p->p.x).($a)
  88.283 ns (1 allocation: 896 bytes)

julia> @btime [ z.x for z in $a ]
  109.578 ns (2 allocations: 912 bytes)

julia> @btime map(p->p.x, $a)
  163.485 ns (3 allocations: 944 bytes)

julia> @btime getfield.($a,:x)
  1.586 ?s (101 allocations: 4.00 KiB)

julia> a = [Point(i,j) for i = 1:100 for j = 1:100]

julia> @btime getfield.($a,:x);
  160.845 ?s (10002 allocations: 390.70 KiB)

julia> @btime (p->p.x).($a);
  9.817 ?s (2 allocations: 78.20 KiB)

julia> @btime map(p->p.x, $a);
  8.306 ?s (3 allocations: 78.22 KiB)

julia> @btime [ z.x for z in $a ];
  8.306 ?s (3 allocations: 78.22 KiB)
Run Code Online (Sandbox Code Playgroud)

getfield总是比其他方法慢 10~20 倍,所以最干净的方法不是高效的。但似乎这种情况在未来会有所改善,我们将为此提供一个语法糖?:Make .a syntactic sugar for i->i.a #22710