# Split vector into N (potentially unequal length) subvectors?

**URL:** https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548
**Category:** General Usage
**Created:** [December 23, 2021, 8:16pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548 "2021-12-23T20:16:05Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![markmbaum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/markmbaum/32/32745_2.png) [@markmbaum](https://discourse.julialang.org/u/markmbaum)
#### Post date: [December 23, 2021, 8:16pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/1 "2021-12-23T20:16:05Z")

</div>

Is there a convenience function for splitting a vector into `N` subvectors? For example, if you had a length-10 vector and called the function to split it into 3 parts, you would get three vectors back, two with length 3 and another with length 4. The subvectors contain all the original items. I see many references to `IterTools.partition` but it performs a slightly different task.

I could write a little function to do this, but I wanted to see if one is already available.

---

<div class="post-metadata">

### Author: ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)
#### Post date: [December 23, 2021, 9:22pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/2 "2021-12-23T21:22:48Z")

</div>

`Iterators.partition` is the only builtin I’m aware of that comes close to this purpose. To get the “long tail” partition, rather than the “short tail” given by `Iterators.partition`, I’d do something like this:

```julia
function partitionvec(x,stride,longtail::Bool=true)
    # longtail=true to lengthen the last entry with the leftovers
    # longtail=false to place the leftovers in their own entry
    stride > 0 || error("stride must be positive") # doesn't handle negative strides
    starts = firstindex(x):stride:lastindex(x)-longtail*stride # where to start each subvector
    return [view(x,starts[i]:get(starts,i+1,lastindex(x)+1)-1) for i in eachindex(starts)]
end

```

---

<div class="post-metadata">

### Author: ![markmbaum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/markmbaum/32/32745_2.png) [@markmbaum](https://discourse.julialang.org/u/markmbaum)
#### Post date: [December 23, 2021, 9:37pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/3 "2021-12-23T21:37:44Z")

</div>

Yeah I decided just to write a really explicit version

```julia
function makechunks(X::AbstractVector{T}, n::Int) where {T}
    L = length(X)
    c = L ÷ n
    Y = Vector{Vector{T}}(undef, n)
    idx = 1
    for i ∈ 1:n-1
        Y[i] = X[idx:idx+c-1]
        idx += c 
    end
    Y[end] = X[idx:end]
    return Y
end

```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [December 23, 2021, 9:55pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/4 "2021-12-23T21:55:46Z")

</div>

> [@markmbaum](#):
>
> Yeah I decided just to write a really explicit version

You might want to use views instead to avoid copies. Also, the whole thing can be made more compact with a comprehension:

```julia
@views function makechunks(X::AbstractVector, n::Integer)
    c = length(X) ÷ n
    return [X[1+c*k:(k == n-1 ? end : c*k+c)] for k = 0:n-1]
end

```

---

<div class="post-metadata">

### Author: ![markmbaum](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/markmbaum/32/32745_2.png) [@markmbaum](https://discourse.julialang.org/u/markmbaum)
#### Post date: [December 23, 2021, 11:08pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/5 "2021-12-23T23:08:20Z")

</div>

Yes that’s all fair. It’s not a performance-critical bit of code for me at the moment so I wasn’t bothering. I’m just using it to split up some items before calling a function on the groups within a `@threads` loop.

---

<div class="post-metadata">

### Author: ![takbal](https://avatars.discourse-cdn.com/v4/letter/t/f0a364/32.png) [@takbal](https://discourse.julialang.org/u/takbal)
#### Post date: [December 28, 2022, 3:00pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/6 "2022-12-28T15:00:13Z")

</div>

This approach seems to be not the best for divisioning data for parallel execution. Consider

```julia
julia> makechunks(collect(1:11), 4)
4-element Vector{SubArray{Int64, 1, Vector{Int64}, Tuple{UnitRange{Int64}}, true}}:
 [1, 2]
 [3, 4]
 [5, 6]
 [7, 8, 9, 10, 11]

```

Splitting data like this is going to bottleneck on the last one that contains the remainder, therefore, at worst the entire processing runs potentlally close to twice as slow as it could be.

I believe this is better:

```julia
function equal_partition(n::Int64, parts::Int64)
    if n < parts
        return [x:x for x in 1:n]
    end
    starts = push!(Int64.(round.(1:n/parts:n)), n+1)
    return [starts[i]:starts[i+1]-1 for i in 1:length(starts)-1 ]
end

function equal_partition(V::AbstractVector, parts::Int64)
    ranges = equal_partition(length(V), parts)
    return [view(V,range) for range in ranges]
end

julia> equal_partition(collect(1:11), 4)
4-element Vector{SubArray{Int64, 1, Vector{Int64}, Tuple{UnitRange{Int64}}, true}}:
 [1, 2, 3]
 [4, 5]
 [6, 7, 8]
 [9, 10, 11]

```

Edited to work better if n \< parts (in which case it returns a smaller array).

---

<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: [December 28, 2022, 4:02pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/7 "2022-12-28T16:02:38Z")

</div>

certainly not champions of efficiency, but just to play with Julia’s possibilities

```julia

parts(n,p,pts=Int[])= cld(n,p)==n/p ? (return push!(pts,fill(cld(n,p),p)...)) : parts(n-cld(n,p),p-1,push!(pts,cld(n,p)))

prng(n,p)=accumulate((s,c)->s.stop+1 : s.stop+c , parts(n,p);init=1:0)

v=rand(1:10,13)
getindex.(Ref(v),prng(length(v),4))
julia> getindex.(Ref(v),prng(length(v),4))
4-element Vector{Vector{Int64}}:
 [10, 5, 3, 8]
 [10, 1, 2]
 [4, 1, 3]
 [2, 6, 9]

julia> v=rand(1:10,10)
julia> getindex.(Ref(v),prng(length(v),4))
4-element Vector{Vector{Int64}}:
 [1, 6, 6]
 [3, 3, 2]
 [6, 6]
 [7, 9]

```

PS  
This should ensure that the maximum difference between the subvector sizes is 1.

---

<div class="post-metadata">

### Author: ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)
#### Post date: [December 28, 2022, 5:52pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/8 "2022-12-28T17:52:49Z")

</div>

I was recently introduced to this package:

> **[GitHub - m3g/ChunkSplitters.jl: Simple chunk splitters for parallel loop...](https://github.com/m3g/ChunkSplitters.jl)**
>
> Simple chunk splitters for parallel loop executions - GitHub - m3g/ChunkSplitters.jl: Simple chunk splitters for parallel loop executions

Just to spread it a bit, seems like it is what people in this thread wants to do 🙂

Kind regards

---

<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: [December 28, 2022, 6:31pm UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/9 "2022-12-28T18:31:18Z")

</div>

This simple formula appears to give a scattered partition of the indexes

```julia
f(n,k)= [collect(i:k:n) for i in 1:k]

```

---

<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: [March 3, 2023, 9:58am UTC](https://discourse.julialang.org/t/split-vector-into-n-potentially-unequal-length-subvectors/73548/10 "2023-03-03T09:58:34Z")

</div>

using `parts()` and the `partby` iterator as defined [here](https://github.com/JuliaCollections/IterTools.jl/issues/99)

you could get

```julia
parts(n,p)= (np=fill(div(n,p),p); np[1:rem(n,p)].+=1; np)
collect(partby(itr,parts(length(itr),4)))

```
