# Flatten to a vector

**URL:** <https://discourse.julialang.org/t/flatten-to-a-vector/30408>\
**Category:** General Usage\
**Tags:** question, array, data\_structures\
**Created:** [October 28, 2019, 4:42pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408 "2019-10-28T16:42:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [October 28, 2019, 4:42pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/1 "2019-10-28T16:42:15Z")

</div>

Sorry @Raf, I can’t seem to find the documentation for this simple question:

Is there a way for `Flatten.flatten` to return a `Vector` instead of a `Tuple` of the parameters?

Right now I simply do:

```julia
[flatten(mystruct)...]

```

Thanks!

---

<div class="post-metadata">

**Author:** ![Orbots](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/orbots/32/3392_2.png) [@Orbots](https://discourse.julialang.org/u/Orbots)\
**Post date:** [October 28, 2019, 7:18pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/2 "2019-10-28T19:18:03Z")

</div>

I usually use `reduce(vcat,A)` but never timed it. Let’s do it!

```julia
julia> using Base.Iterators

julia> A = map(i->rand(10),1:1000);

julia> @btime reduce(vcat,A);
  10.179 μs (2 allocations: 78.20 KiB)

julia> @btime [flatten(A)...];
  639.579 μs (30014 allocations: 1019.94 KiB)

```

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [October 28, 2019, 7:39pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/3 "2019-10-28T19:39:49Z")

</div>

That’s cool, but I’m trying to flatten a `struct`, not a vector of vectors. Actually, a vector of structs…

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 28, 2019, 10:49pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/4 "2019-10-28T22:49:13Z")

</div>

Flatten isn’t for vectors - its all compile time and we don’t know vector length at compile time.

It flattens arbitrary nested structs and tuples where the fields are known at compile time.

Edit: you are actually timing Base.Iterators.flatten, not Flatten.jl. You would usually find that flattening structs at runtime is best measured in `ns`. It might even have a similar runtime fro a problem as large as the one you time above if it was using tuples, but the compile time would be ridiculous.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 28, 2019, 10:49pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/5 "2019-10-28T22:49:46Z")

</div>

There used to be an argument or flattening to `Vector` but as I added all the arbitrary type flattening it got confusing having so many types in the method call.

So now you just manually do `[flatten(x, Real)...]`. That’s all the internal method did anyway and its actually less characters than it was before 🙂

I should probably update the docs a little.

Edit: you might also want to convert the tuple to `SVector` where performance matters, as it wont allocate.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [October 29, 2019, 6:51am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/6 "2019-10-29T06:51:31Z")

</div>

Thanks!

In my application I want to flatten a known number of `struct`s to an iterable container. Each `struct` has 4 fields (`UInt8`), and there are 4 `struct`s, which would result in a tuple with 16 (`UInt8`) elements. So an `SVector` would make sense. So something like this (on my phone now, so will check my self later)?

```julia
x = [MyStruct() for _ in 1:4]
flatten(x..., SVector{UInt8, 16})

```

(back on computer) Apparently not… I’m all of a sudden unsure on how to do this with `Flatten`… I could forgo my custom type and just use a static vector:

```julia
using StaticArrays
A = SVector{4, UInt8}
x = (A(rand(UInt8, 4)) for _ in 1:4)
reduce(vcat, x)

```

How exactly, and would it be any better, do I flatten `x` with `Flatten`:

```julia
using Flatten
struct B
    x1::UInt8
    x2::UInt8
    x3::UInt8
    x4::UInt8
end
x = (B(rand(UInt8, 4)...) for _ in 1:4)

```

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 29, 2019, 7:54am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/7 "2019-10-29T07:54:48Z")

</div>

You could look at [https://github.com/pao/StrPack.jl](https://github.com/pao/StrPack.jl). Not sure how well it works since it seems to not have been extensively maintained.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 29, 2019, 7:55am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/8 "2019-10-29T07:55:50Z")

</div>

Cant you just do `SVector(flatten(x, Real))` ? (or whatever type you want besides Real)

The type in the flatten signature is the types that will be extracted from the struct! So `flatten(x, Int)` will get all the `Int` and `SVector(flatten(x, Int))` will put all the `Int` into an `SVector`.

Flatten args are like: `flatten(obj, extracttype::Type, ignoretype::Type)`, returning a tuple where extract is the type/union to take and ignore is the type/union to ignore. It’s totally arbitrary what actually gets flattened now, but it always produces a tuple. Then you can do whatever you want with the tuple.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 29, 2019, 7:56am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/9 "2019-10-29T07:56:32Z")

</div>

Flatten.jl does a lot more than StrPack and is maintained. It’s just very abstract and kinda weird.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [October 29, 2019, 8:01am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/10 "2019-10-29T08:01:56Z")

</div>

Sorry, it was unclear to me that `Flatten` here referred to a package.

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [October 29, 2019, 8:03am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/11 "2019-10-29T08:03:40Z")

</div>

> [@Raf](#):
>
> Cant you just do `SVector(flatten(x, Real))` ?

No, because `x` in this example is a vector of structs. But I might be missing something. In this MWE, that won’t work:

```julia
using Flatten, StaticArrays
struct B
    x1::UInt8
    x2::UInt8
    x3::UInt8
    x4::UInt8
end
x = [B(rand(UInt8, 4)...) for _ in 1:4]

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 29, 2019, 8:07am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/12 "2019-10-29T08:07:24Z")

</div>

You can’t flatten vectors as the length is unknown to the compiler. Try with a tuple or SVector:

```julia
using Flatten
struct B
    x1::UInt8
    x2::UInt8
    x3::UInt8
    x4::UInt8
end

julia> x = Tuple(B(rand(UInt8, 4)...) for _ in 1:4)

julia> using StaticArrays

julia> SVector(flatten(x))
16-element SArray{Tuple{16},UInt8,1,16} with indices SOneTo(16):
 0x81
 0xa4
 0x41
 0xef
 0xf6
 0xca
 0x9b
 0x7d
 0xb6
 0xe7
 0xb4
 0xd7
 0x69
 0x14
 0xf7
 0x97

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 29, 2019, 8:08am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/13 "2019-10-29T08:08:57Z")

</div>

Also of interest:

```julia
julia> @btime SVector(flatten($x))
  0.020 ns (0 allocations: 0 bytes)
16-element SArray{Tuple{16},UInt8,1,16} with indices SOneTo(16):
 0x81
 0xa4
 0x41
 0xef
 0xf6
 0xca
 0x9b
 0x7d
 0xb6
 0xe7
 0xb4
 0xd7
 0x69
 0x14
 0xf7
 0x97

```

---

<div class="post-metadata">

**Author:** ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)\
**Post date:** [October 29, 2019, 8:11am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/14 "2019-10-29T08:11:27Z")

</div>

Thank you so much @Raf, this is great. I was trying to `(B(...) for _ in 1:4)` before instead of the explicit `Tuple(...)` version and got stuck on that.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 29, 2019, 8:19am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/15 "2019-10-29T08:19:57Z")

</div>

It good to know what is confusing about the package, I’ll make it clearer in the docs that length of objects has to be known at compile time, and we are specifically flattening _fields_, which `Array` doesn’t have.

---

<div class="post-metadata">

**Author:** ![tallakt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tallakt/32/46978_2.png) [@tallakt](https://discourse.julialang.org/u/tallakt)\
**Post date:** [February 16, 2023, 7:56pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/16 "2023-02-16T19:56:56Z")

</div>

I have been using `vcat(a, b..., c, d)` etc for this (in the vector case). Would have liked to see a proper `flatten` though, as well as `flat_map`.

I think it could be done for a struct by using the dynamic lookup functions.

```julia
flatten_struct = x -> [getfield(x, n) for n = fieldnames(typeof(x))]

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [February 16, 2023, 10:03pm UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/17 "2023-02-16T22:03:08Z")

</div>

> [@tallakt](#):
>
> Would have liked to see a proper `flatten` though, as well as `flat_map`.

```julia
julia> using FlexiMaps

julia> flatten([1:2, 5:10, 1:0])
8-element Vector{Int64}:
<...>

julia> flatmap(i -> 1:i, [1, 3, 2])
6-element Vector{Int64}:
 1
 1
 2
 3
 1
 2

```

> [@tallakt](#):
>
> I think it could be done for a struct by using the dynamic lookup functions.

This does a single level of struct flattening. It can be what one needs, but `Flatten.jl` main usecase is recursive flattening AFAIK.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 17, 2023, 9:50am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/18 "2023-02-17T09:50:49Z")

</div>

in this example.  
How does flatten() stop unnesting at the rational number level and not unpack the numerators and denominators as well?  
I’d be interested in understanding it in principle as well, without the implementation details that I probably wouldn’t be able to understand.

```julia
using Flatten

struct NR
    q1::Rational{Int64}
    q2::Rational{Int64}
end

NSR = Tuple(NR(nn...) for _ in 1:4)

nn=Tuple(NR((Rational(rand(1:10,2)...) for _ in 1:2)...) for _ in 1:4)
julia> flatten(nn)
(5//2, 2//1, 2//1, 7//9, 2//3, 3//5, 9//5, 3//5)

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [February 17, 2023, 10:49am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/19 "2023-02-17T10:49:23Z")

</div>

This is just because you are not passing any arguments to `flatten`, and the default behavior is to flatten `Real`. Maybe that’s not well enough documented.

If you want the inner values, use `flatten(nn, Int64)` and it will look inside the `Rational` numbers for `Int64`.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 17, 2023, 10:54am UTC](https://discourse.julialang.org/t/flatten-to-a-vector/30408/20 "2023-02-17T10:54:57Z")

</div>

Okay. Thank you.  
I don’t need to unpack the rationali.  
I was wondering how the function could be so “smart” that it stops at the right point.  
So, conceptually, the recursive function (with default parameters) unpacks everything that isn’t Real?

[Next page](https://discourse.julialang.org/t/flatten-to-a-vector/30408.md?page=2)
