 # Unpack array of tuples and structs

Hello everyone,

I have a question which seems to be kind of related to Convert array of tuples to vector.

Edit : I just realized I can do these things with StructArrays except for the tuple case.
However, I wonder if there is different way this can be done.

Let me give a MWE.

``````julia> struct Input
a
b
end

julia> struct Output
a
b
end

julia> function f1(inp :: Input, x)
return  x*inp.a, x*inp.b
end
f1 (generic function with 1 method)

julia> function f2(inp :: Input, x)
return OutPut(x*inp.a, x*inp.b)
end

julia> inp = Input(2.0,3.0)
Input(2.0, 3.0)

julia> f1(inp, 10)
(20.0, 30.0)

julia> f2(inp, 10)
OutPut(20.0, 30.0)

julia> v = 1:5
1:5
``````

Now, if I input vector v to f1 I get

``````c =f1.(Ref(inp), v)
10-element Array{Tuple{Float64,Float64},1}:
(2.0, 3.0)
(4.0, 6.0)
(6.0, 9.0)
(8.0, 12.0)
(10.0, 15.0)
``````

Question 1:
How can I get the the first, or second element of each tuple into a vector?

``````julia> c[:]
(2.0, 3.0)
``````

which is not what I want.
StructArrays does not seem to help here.It gives the same result.

Now, I can do the following:

``````julia> get_a(op :: Output) = op.a
get_a (generic function with 1 method)

julia> d =f2.(Ref(inp), v)
10-element Array{Output,1}:
Output(2.0, 3.0)
Output(4.0, 6.0)
Output(6.0, 9.0)
Output(8.0, 12.0)
Output(10.0, 15.0)

julia> get_a.(d)
10-element Array{Float64,1}:
2.0
4.0
6.0
8.0
10.0
``````

This works great.
I was wondering if there was another way to achieve something similar.
I hoped that @unpack from Parameters.jl could do something like

``````julia> @unpack a, b .= d
ERROR: LoadError: Expression needs to be of form `a, b = c`
Stacktrace:
 error(::String) at ./error.jl:33
 @unpack(::LineNumberNode, ::Module, ::Any) at /home/omerchiers/.julia/packages/Parameters/l76EM/src/Parameters.jl:743
in expression starting at none:1
``````

but unfortunately it doesn’t work.

Question 2:
Again, with StructArrays I can achieve my goal.
But still I was wondering if there is some way to use @unpack like that?

Olivier

1 Like

I love comprehensions (did I say that already?):

``````[ x for x in c ]
5-element Array{Float64,1}:
2.0
4.0
6.0
8.0
10.0
``````
1 Like

that’s great!
thanks a lot

1 Like

Arguably the more idiomatic solution here is `first.(c)` and `last.(c)`, more generally you can broadcast `getindex` like `getindex.(c, 1)`

2 Likes

EDIT: I totally missed the point. I delete the post.

Thanks for the suggestion.

The Input struct was probably not really necessary in my MWE.
I just wanted to show two functions: one that outputs a tuple and another one that outputs some struct.
And how to handle these two cases when outputting a vector of those.

But thanks anyway.

ooh that’s also very cool.
but now this makes me wonder why the following things work as expected

• getindex.(c,1)
• c
• c[:]

but this

• c[:]

does not

That’s equivalent to:

``````temp = c[:]
temp
``````

Try running those two lines and look at what `temp` ends up as.

In other words, the expression `c[:]` creates a copy of `c` and then takes the first element of that copy. It’s a valid thing to do, but not a very useful one.

2 Likes

yes indeed, now it makes sense.

``````julia> c == c[:]
true
``````

hence

``````julia> c == c[:]
true
``````

Totally logical, but somehow I find it disturbing.
Thanks a lot for this very insightful example.