假设我有一个元组数组:
arr = [(1,2), (3,4), (5,6)]
使用python我可以zip(*arr) == [(1, 3, 5), (2, 4, 6)]
在朱莉娅中这相当于什么?
答案 0 :(得分:9)
您可以使用zip()
函数(docs here)在Julia中实现相同的功能。 zip()
期望使用许多元组,因此您必须使用splatting operator ...
来提供参数。同样在Julia中,您必须使用collect()
函数将迭代变换为数组(如果您愿意)。
以下是这些功能:
arr = [(1,2), (3,4), (5,6)]
# wtihout splatting
collect(zip((1,2), (3,4), (5,6)))
# Output is a vector of arrays:
> ((1,3,5), (2,4,6))
# same results with splatting
collect(zip(arr...))
> ((1,3,5), (2,4,6))
答案 1 :(得分:3)
朱莉娅:
使用......
for r in zip(arr...)
println(r)
end
答案 2 :(得分:1)
作为喷溅的替代方法(因为它非常慢),您可以执行以下操作:
unzip(a) = map(x->getfield.(a, x), fieldnames(eltype(a)))
这很快。
julia> using BenchmarkTools
julia> a = collect(zip(1:10000, 10000:-1:1));
julia> @benchmark unzip(a)
BenchmarkTools.Trial:
memory estimate: 156.45 KiB
allocs estimate: 6
--------------
minimum time: 25.260 μs (0.00% GC)
median time: 31.997 μs (0.00% GC)
mean time: 48.429 μs (25.03% GC)
maximum time: 36.130 ms (98.67% GC)
--------------
samples: 10000
evals/sample: 1
通过比较,我还没有看到完整的内容:
@time collect(zip(a...))
答案 3 :(得分:1)
还有 Unzip.jl 包:
julia> using Unzip
julia> unzip([(1,2), (3,4), (5,6)])
([1, 3, 5], [2, 4, 6])
这似乎比选定的答案要快一点:
julia> using Unzip, BenchmarkTools
julia> a = collect(zip(1:10000, 10000:-1:1));
julia> unzip_ivirshup(a) = map(x->getfield.(a, x), fieldnames(eltype(a))) ;
julia> @btime unzip_ivirshup($a);
18.439 μs (4 allocations: 156.41 KiB)
julia> @btime unzip($a); # unzip from Unzip.jl is faster
12.798 μs (4 allocations: 156.41 KiB)
julia> unzip(a) == unzip_ivirshup(a) # check output is the same
true
答案 4 :(得分:0)
紧跟@ivirshup的答案,我想添加一个仍然是迭代器的版本
unzip(a) = (getfield.(a, x) for x in fieldnames(eltype(a)))
在使用前不评估结果。比较时甚至可以(非常轻微)提高速度
@benchmark a1, b1 = unzip(a)
BenchmarkTools.Trial:
memory estimate: 156.52 KiB
allocs estimate: 8
--------------
minimum time: 33.185 μs (0.00% GC)
median time: 76.581 μs (0.00% GC)
mean time: 83.808 μs (18.35% GC)
maximum time: 7.679 ms (97.82% GC)
--------------
samples: 10000
evals/sample: 1
vs。
BenchmarkTools.Trial:
memory estimate: 156.52 KiB
allocs estimate: 8
--------------
minimum time: 33.914 μs (0.00% GC)
median time: 39.020 μs (0.00% GC)
mean time: 64.788 μs (16.52% GC)
maximum time: 7.853 ms (98.18% GC)
--------------
samples: 10000
evals/sample: 1
答案 5 :(得分:0)
我将添加一个基于以下简单宏的解决方案
"""
@unzip xs, ys, ... = us
will expand the assignment into the following code
xs, ys, ... = map(x -> x[1], us), map(x -> x[2], us), ...
"""
macro unzip(args)
args.head != :(=) && error("Expression needs to be of form `xs, ys, ... = us`")
lhs, rhs = args.args
items = isa(lhs, Symbol) ? [lhs] : lhs.args
rhs_items = [:(map(x -> x[$i], $rhs)) for i in 1:length(items)]
rhs_expand = Expr(:tuple, rhs_items...)
esc(Expr(:(=), lhs, rhs_expand))
end
由于它只是一个句法扩展,不应该有任何性能或类型不稳定的问题。与其他基于 fieldnames
的解决方案相比,这具有在数组元素类型为抽象时也能工作的优点。例如,同时
julia> unzip_get_field(a) = map(x->getfield.(a, x), fieldnames(eltype(a)));
julia> unzip_get_field(Any[("a", 3), ("b", 4)])
ERROR: ArgumentError: type does not have a definite number of fields
宏版本仍然有效:
julia> @unzip xs, ys = Any[("a", 3), ("b",4)]
(["a", "b"], [3, 4])