2017-02-20 51 views
2

在Python中,可以使用*运算符来解包迭代。Julia splat运算符解包

In [1]: head, *tail = [1, 2, 3, 4, 5] 

In [2]: head 
Out[2]: 1 

In [3]: tail 
Out[3]: [2, 3, 4, 5] 

我想在朱莉娅产生相同的行为。我认为相当于...的操作符可以工作,但它似乎只是在这种情况下产生一个错误。

julia> head, tail... = [1, 2, 3, 4, 5] 
ERROR: syntax: invalid assignment location "tail..." 

我能够使用以下内容生成我想要的结果,但这是一个丑陋的解决方案。

julia> head, tail = A[1], A[2:end] 
(1,[2,3,4,5]) 

我能解开阵列,使得tail将包含其余项目使用图示(...)运算符head后?如果不是,最干净的选择是什么?


编辑:此功能已在#2626被提出。它看起来将成为1.0版本的一部分。

+0

我不认为'head,tail = A [1],A [2:end]'是丑陋的,它明确地告诉'head'和'tail'是什么。如果'A'没有潜在的用法,使用'head,tail = shift!(A),A'会更有效一些。 – Gnimuc

+1

@Gnimuc随着更多项目需要解包,它变得越来越丑陋。 'a,b,c,* d = [1,2,3,4,5]'比使用大量索引或移位! :) –

+0

这听起来像一个宏的工作。 –

回答

2

这的确听起来像一个宏工作:

function unpack(lhs, rhs) 
    len = length(lhs.args) 
    if len == 1 
     # just remove the splatting 
     l, is_splat = remove_splat(lhs.args[1]) 
     return :($l = $(esc(rhs))) 
    else 
     new_lhs = :() 
     new_rhs = quote 
      tmp = $(esc(rhs)) 
      $(Expr(:tuple)) 
     end 
     splatted = false 
     for (i, e) in enumerate(lhs.args) 
      l, is_splat = remove_splat(e) 
      if is_splat 
       splatted && error("Only one splatting operation allowed on lhs") 
       splatted = true 
       r = :(tmp[$i:end-$(len-i)]) 
      elseif splatted 
       r = :(tmp[end-$(len-i)]) 
      else 
       r = :(tmp[$i]) 
      end 
      push!(new_lhs.args, l) 
      push!(new_rhs.args[4].args, r) 
     end 
     return :($new_lhs = $new_rhs) 
    end 
end 

remove_splat(e::Symbol) = esc(e), false 

function remove_splat(e::Expr) 
    if e.head == :(...) 
     return esc(e.args[1]), true 
    else 
     return esc(e), false 
    end 
end 

macro unpack(expr) 
    if Meta.isexpr(expr, :(=)) 
     if Meta.isexpr(expr.args[1], :tuple) 
      return unpack(expr.args[1], expr.args[2]) 
     else 
      return unpack(:(($(expr.args[1]),)), expr.args[2]) 
     end 
    else 
     error("Cannot parse expression") 
    end 
end 

它也没有很好的测试,但基本的东西工作:

julia> @unpack head, tail... = [1,2,3,4] 
(1,[2,3,4]) 

julia> @unpack head, middle..., tail = [1,2,3,4,5] 
(1,[2,3,4],5) 

几个朱莉娅陷阱:

x,y = [1,2,3] #=> x = 1, y = 2 

a = rand(3) 
a[1:3], y = [1,2,3] #=> a = [1.0,1.0,1.0], y = 2 

宏遵循此行为

@unpack a[1:3], y... = [1,2,3] 
#=> a=[1.0,1.0,1.0], y=[2,3] 
相关问题