在朱莉娅解压缩一系列元组

时间:2016-04-01 23:39:04

标签: julia

假设我有一个元组数组:

arr = [(1,2), (3,4), (5,6)]

使用python我可以zip(*arr) == [(1, 3, 5), (2, 4, 6)]

在朱莉娅中这相当于什么?

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])