# Optimize splitting vector of strings

**URL:** https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924
**Category:** Performance
**Tags:** strings
**Created:** [August 7, 2024, 3:53pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924 "2024-08-07T15:53:29Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [August 7, 2024, 3:53pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/1 "2024-08-07T15:53:29Z")

</div>

I am learning how to optimize julia code and came up with the following MWE:

```julia
using BenchmarkTools, Profile

strvec = ["AA entryA", "BBC entryB", "CCM entryC"]

function split_vec(strvec)
    mat = stack(split.(strvec), dims = 1)
    col1 = first.(mat[:, 1], 2)
    col2 = Vector{String}(undef, length(col1))

    idx_nAA = col1 .!= "AA"
    col2[idx_nAA, :] = last.(mat[idx_nAA, 1], 1)
    col2[idx_nAA .== 0, :] .= ""
    return stack([col1, col2, mat[:, 2]])
end

split_vec(strvec)
@benchmark split_vec(strvec)
@Profile.profile for i in 1:Int(1e4) split_vec(strvec) end

Profile.print()

```

Desired Output:

```julia
3×3 Matrix{AbstractString}:
 "AA" "" "entryA"
 "BB" "C" "entryB"
 "CC" "M" "entryC"

```

Benchmark:

```julia
BenchmarkTools.Trial: 10000 samples with 5 evaluations.
 Range (min … max): 6.470 μs … 3.040 ms ┊ GC (min … max): 0.00% … 99.17%
 Time (median): 8.014 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 9.368 μs ± 30.440 μs ┊ GC (mean ± σ): 3.22% ± 0.99%

  ▄█▇▅▄▅▆▅▅▆▅▅▄▄▃▃▂▁▁ ▁ ▅▃▂▃▃▂▃▂▂▂▁▁▁▁ ▂
  ██████████████████████▇▇█▇▇▇█▇▇██████████████████▇▇▇▇▇▆▆▅▅ █
  6.47 μs Histogram: log(frequency) by time 17.4 μs <

 Memory estimate: 2.62 KiB, allocs estimate: 34.

```

Profile:

```julia
Overhead ╎ [+additional indent] Count File:Line; Function
=========================================================
  ╎105 @Base/client.jl:552; _start()
  ╎ 105 @Base/client.jl:333; exec_options(opts::Base.JLOptions)
  ╎ 105 @Base/client.jl:416; run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_file::Bool, color_set::Bool)
  ╎ 105 @Base/essentials.jl:889; invokelatest
  ╎ 105 @Base/essentials.jl:892; #invokelatest#2
  ╎ 105 @Base/client.jl:432; (::Base.var"#1013#1015"{Bool, Bool, Bool})(REPL::Module)
  ╎ ╎ 105 …ot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:375; run_repl(repl::REPL.AbstractREPL, consumer::Any)
  ╎ ╎ 105 …ot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:389; run_repl(repl::REPL.AbstractREPL, consumer::Any; backend_on_current_task::Bool, backe…
  ╎ ╎ 105 …ot-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:228; kwcall(::NamedTuple, ::typeof(REPL.start_repl_backend), backend::REPL.REPLBackend, c…
  ╎ ╎ 105 …t-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:231; start_repl_backend(backend::REPL.REPLBackend, consumer::Any; get_module::Function)
  ╎ ╎ 105 …t-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:246; repl_backend_loop(backend::REPL.REPLBackend, get_module::Function)
  ╎ ╎ ╎ 105 …-10/usr/share/julia/stdlib/v1.10/REPL/src/REPL.jl:150; eval_user_input(ast::Any, backend::REPL.REPLBackend, mod::Module)
  ╎ ╎ ╎ 105 @Base/boot.jl:385; eval
  ╎ ╎ ╎ 105 REPL[6]:1; top-level scope
  ╎ ╎ ╎ 105 …r/share/julia/stdlib/v1.10/Profile/src/Profile.jl:27; macro expansion
 2╎ ╎ ╎ 105 REPL[6]:1; macro expansion
  ╎ ╎ ╎ ╎ 12 REPL[3]:2; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2767; stack
  ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2767; #stack#184
  ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2799; _stack
  ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2807; _stack
  ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2839; _typed_stack
  ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2847; _typed_stack
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:2856; _dim_stack
  ╎ ╎ ╎ ╎ ╎ 1 @Base/iterators.jl:652; peel
  ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:945; iterate
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:945; iterate
 1╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/essentials.jl:13; getindex
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:2868; _dim_stack
 1╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:2877; _dim_stack!(::Val{1}, B::Matrix{SubString{String}}, x1::Vector{SubString{String}}, xrest::Base.It…
  ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:903; materialize
  ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:928; copy
  ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:956; copyto!
  ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:1003; copyto!
  ╎ ╎ ╎ ╎ ╎ 10 @Base/simdloop.jl:77; macro expansion
  ╎ ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:1004; macro expansion
  ╎ ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:636; getindex
  ╎ ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:682; _broadcast_getindex
  ╎ ╎ ╎ ╎ ╎ 10 @Base/broadcast.jl:709; _broadcast_getindex_evalf
  ╎ ╎ ╎ ╎ ╎ ╎ 10 @Base/strings/util.jl:633; split
  ╎ ╎ ╎ ╎ ╎ ╎ 10 @Base/strings/util.jl:633; #split#488
  ╎ ╎ ╎ ╎ ╎ ╎ 10 @Base/strings/util.jl:626; split
  ╎ ╎ ╎ ╎ ╎ ╎ 10 @Base/strings/util.jl:628; #split#487
  ╎ ╎ ╎ ╎ ╎ ╎ 10 @Base/array.jl:759; collect
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:769; _collect(cont::UnitRange{Int64}, itr::Base.SplitIterator{String, typeof(isspace)}, ::Base.HasEltype…
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:713; _similar_for
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:833; similar
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:842; similar
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/boot.jl:486; Array
 2╎ ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/boot.jl:477; Array
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:770; _collect(cont::UnitRange{Int64}, itr::Base.SplitIterator{String, typeof(isspace)}, ::Base.HasEltype…
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/util.jl:555; iterate
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/util.jl:556; iterate
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/search.jl:170; findnext(testf::typeof(isspace), s::String, i::Int64)
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:171; nextind
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:175; _nextind_str(s::String, i::Int64)
 1╎ ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/promotion.jl:521; ==
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:771; _collect(cont::UnitRange{Int64}, itr::Base.SplitIterator{String, typeof(isspace)}, ::Base.HasEltype…
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:1119; push!
 2╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:1072; _growend!
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 3 @Base/array.jl:772; _collect(cont::UnitRange{Int64}, itr::Base.SplitIterator{String, typeof(isspace)}, ::Base.HasEltype…
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/strings/util.jl:556; iterate
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/search.jl:166; findnext(testf::typeof(isspace), s::String, i::Int64)
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:521; isvalid(s::String, i::Int64)
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/basic.jl:208; checkbounds
 1╎ ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/int.jl:514; <=
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/search.jl:170; findnext(testf::typeof(isspace), s::String, i::Int64)
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:171; nextind
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:175; _nextind_str(s::String, i::Int64)
 1╎ ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/promotion.jl:521; ==
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/util.jl:569; iterate
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:42; SubString
  ╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:41; SubString
 1╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:30; SubString{String}(s::String, i::Int64, j::Int64)
 2╎ ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/int.jl:0; _collect(cont::UnitRange{Int64}, itr::Base.SplitIterator{String, typeof(isspace)}, ::Base.HasEltype, is…
  ╎ ╎ ╎ ╎ 3 REPL[3]:3; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:1291; getindex
  ╎ ╎ ╎ ╎ 1 @Base/multidimensional.jl:889; _getindex
  ╎ ╎ ╎ ╎ 1 @Base/multidimensional.jl:901; _unsafe_getindex
  ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:831; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:420; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/boot.jl:486; Array
 1╎ ╎ ╎ ╎ ╎ 1 @Base/boot.jl:477; Array
  ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:903; materialize
  ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:928; copy
  ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:956; copyto!
  ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:1003; copyto!
  ╎ ╎ ╎ ╎ ╎ 2 @Base/simdloop.jl:77; macro expansion
  ╎ ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:1004; macro expansion
  ╎ ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:636; getindex
  ╎ ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:681; _broadcast_getindex
  ╎ ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:705; _getindex
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:675; _broadcast_getindex
 1╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/essentials.jl:13; getindex
  ╎ ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:682; _broadcast_getindex
  ╎ ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:709; _broadcast_getindex_evalf
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/basic.jl:693; first(s::SubString{String}, n::Int64)
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:292; getindex
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:43; SubString
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:47; SubString
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/substring.jl:41; SubString
 1╎ ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/strings/string.jl:174; _nextind_str(s::String, i::Int64)
  ╎ ╎ ╎ ╎ 27 REPL[3]:4; split_vec(strvec::Vector{String})
27╎ ╎ ╎ ╎ 27 @Base/boot.jl:477; Array
  ╎ ╎ ╎ ╎ 1 REPL[3]:6; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:903; materialize
  ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:928; copy
  ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:223; similar
  ╎ ╎ ╎ ╎ 1 @Base/broadcast.jl:226; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:876; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:877; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/bitarray.jl:71; BitArray
 1╎ ╎ ╎ ╎ ╎ 1 @Base/bitarray.jl:39; BitArray
  ╎ ╎ ╎ ╎ 1 REPL[3]:7; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:1396; setindex!
  ╎ ╎ ╎ ╎ 1 @Base/multidimensional.jl:944; _setindex!
  ╎ ╎ ╎ ╎ 1 @Base/multidimensional.jl:955; _unsafe_setindex!(::IndexLinear, ::Vector{String}, ::Vector{SubString{String}}, ::Base.LogicalIndex{…
  ╎ ╎ ╎ ╎ 1 @Base/cartesian.jl:66; macro expansion
  ╎ ╎ ╎ ╎ ╎ 1 @Base/multidimensional.jl:842; iterate
  ╎ ╎ ╎ ╎ ╎ 1 @Base/bitarray.jl:121; _blsr
  ╎ ╎ ╎ ╎ ╎ 1 @Base/int.jl:347; &
  ╎ ╎ ╎ ╎ 2 REPL[3]:8; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 2 @Base/broadcast.jl:1244; dotview
  ╎ ╎ ╎ ╎ 2 @Base/views.jl:148; maybeview
  ╎ ╎ ╎ ╎ 2 @Base/subarray.jl:186; view
  ╎ ╎ ╎ ╎ 2 @Base/subarray.jl:223; unsafe_view
  ╎ ╎ ╎ ╎ ╎ 2 @Base/subarray.jl:28; SubArray
  ╎ ╎ ╎ ╎ ╎ 2 @Base/multidimensional.jl:855; ensure_indexable
  ╎ ╎ ╎ ╎ ╎ 2 @Base/multidimensional.jl:792; collect
  ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:839; collect(itr::Base.Generator{Base.LogicalIndex{Int64, BitVector}, typeof(identity)})
  ╎ ╎ ╎ ╎ ╎ 2 @Base/array.jl:723; _array_for
  ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:876; similar
  ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:877; similar
  ╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/boot.jl:486; Array
 2╎ ╎ ╎ ╎ ╎ ╎ 2 @Base/boot.jl:477; Array
  ╎ ╎ ╎ ╎ 57 REPL[3]:9; split_vec(strvec::Vector{String})
  ╎ ╎ ╎ ╎ 57 @Base/abstractarray.jl:2767; stack
  ╎ ╎ ╎ ╎ 57 @Base/abstractarray.jl:2767; #stack#184
  ╎ ╎ ╎ ╎ 57 @Base/abstractarray.jl:2799; _stack
  ╎ ╎ ╎ ╎ 51 @Base/abstractarray.jl:2811; _stack(dims::Function, ::Base.HasShape{1}, iter::Vector{Vector})
  ╎ ╎ ╎ ╎ ╎ 51 @Base/reducedim.jl:357; mapreduce
  ╎ ╎ ╎ ╎ ╎ 51 @Base/reducedim.jl:357; #mapreduce#821
  ╎ ╎ ╎ ╎ ╎ 51 @Base/reducedim.jl:365; _mapreduce_dim
 2╎ ╎ ╎ ╎ ╎ 31 @Base/reduce.jl:440; _mapreduce(f::typeof(eltype), op::typeof(promote_type), ::IndexLinear, A::Vector{Vector})
  ╎ ╎ ╎ ╎ ╎ 29 @Base/abstractarray.jl:241; eltype
29╎ ╎ ╎ ╎ ╎ ╎ 29 @Base/abstractarray.jl:242; eltype
 5╎ ╎ ╎ ╎ ╎ 20 @Base/reduce.jl:443; _mapreduce(f::typeof(eltype), op::typeof(promote_type), ::IndexLinear, A::Vector{Vector})
  ╎ ╎ ╎ ╎ ╎ 15 @Base/abstractarray.jl:241; eltype
15╎ ╎ ╎ ╎ ╎ ╎ 15 @Base/abstractarray.jl:242; eltype
 3╎ ╎ ╎ ╎ 6 @Base/abstractarray.jl:2812; _stack(dims::Function, ::Base.HasShape{1}, iter::Vector{Vector})
  ╎ ╎ ╎ ╎ ╎ 3 @Base/abstractarray.jl:2817; _typed_stack(::Colon, ::Type{AbstractString}, ::Type{Vector}, A::Vector{Vector})
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:2821; _typed_stack(::Colon, ::Type{AbstractString}, ::Type{Vector}, A::Vector{Vector}, Aax::Tuple{Base.On…
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:833; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:420; similar
  ╎ ╎ ╎ ╎ ╎ 1 @Base/boot.jl:487; Array
 1╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/boot.jl:479; Array
 1╎ ╎ ╎ ╎ ╎ 2 @Base/abstractarray.jl:2827; _typed_stack(::Colon, ::Type{AbstractString}, ::Type{Vector}, A::Vector{Vector}, Aax::Tuple{Base.On…
  ╎ ╎ ╎ ╎ ╎ 1 @Base/abstractarray.jl:1118; copyto!(dest::Matrix{AbstractString}, dstart::Int64, src::Vector{SubString{String}})
  ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:363; copyto!
  ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:376; _copyto_impl!
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:353; unsafe_copyto!
  ╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:299; _unsafe_copyto!(dest::Matrix{AbstractString}, doffs::Int64, src::Vector{SubString{String}}, soffs::Int6…
 1╎ ╎ ╎ ╎ ╎ ╎ 1 @Base/array.jl:1021; setindex!
Total snapshots: 106. Utilization: 100% across all threads and tasks. Use the `groupby` kwarg to break down by thread and/or task.

```

What can I do to make this as fast as possible? Can this be done with zero allocations? It seems one of the bottlenecks is calling `stack()`, which I had assumed is already pretty optimized.

---

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [August 7, 2024, 4:11pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/2 "2024-08-07T16:11:50Z")

</div>

One other thing is that the `AA` strings will always be two characters (others are always three) and almost always be only the first entry, but this is not guaranteed.

Thanks for any help!

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [August 7, 2024, 4:12pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/3 "2024-08-07T16:12:25Z")

</div>

idk what constraint you have and what you can assume to be the property of the inputs, but here’s one possibility:

```julia
julia> @b split_vec($strvec)
6.181 μs (35.75 allocs: 2.668 KiB)

julia> function split_vec2(strvec)
           mat = Matrix{String}(undef, length(strvec), 3)
           for i in eachindex(strvec)
               str = strvec[i]
               space_idx = findfirst(' ', str)
               mat[i, 1] = SubString(str, 1:2)
               mat[i, 2] = ifelse(space_idx==3, "", SubString(str, 3:3))
               mat[i, 3] = @view str[space_idx+1:end]
           end
           return mat
       end
split_vec2 (generic function with 1 method)

julia> split_vec2(strvec)
3×3 Matrix{String}:
 "AA" "" "entryA"
 "BB" "C" "entryB"
 "CC" "M" "entryC"

julia> @b split_vec2($strvec)
356.739 ns (12 allocs: 416 bytes)

```

---

<div class="post-metadata">

### Author: ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)
#### Post date: [August 7, 2024, 4:42pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/4 "2024-08-07T16:42:16Z")

</div>

Yes, 10x faster. This seems much more reasonable. Thanks.

---

<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: [August 7, 2024, 4:58pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/5 "2024-08-07T16:58:01Z")

</div>

> [@jling](#):
>
> `mat = Matrix{String}`

This requires the substrings to be copied into `String`s when they are stored in `mat`. If you instead use `Matrix{SubString{String}}`, then it won’t have to copy the strings at all.

Might also be easier to just put `@views` in front of the function, or in front of the `for` loop, and then you can just do:

```julia
mat[i, 1] = str[1:2]
mat[i, 2] = str[ifelse(space_idx==3, 1:0, 3:3)]
mat[i, 3] = str[space_idx+1:end]

```

instead of the explicit `SubString` calls. Notice that I also used the empty range `str[1:0]` instead of `""` so that everything is a substring.

These two changes speed things up by almost a factor of 2 for me, as well as cutting the number of allocations down to 1.

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [August 7, 2024, 5:43pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/6 "2024-08-07T17:43:01Z")

</div>

Ah I tried SubString for matrix but forgot it is parametric… Thanks for the fix;!

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [August 7, 2024, 7:27pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/7 "2024-08-07T19:27:00Z")

</div>

> [@jling](#):
>
> ```julia
> for i in eachindex(strvec)
> str = strvec[i]
> 
> ```

Just two cents, because it seems nicer to write it like this:

```julia
for (i, str) in pairs(strvec)

```

---

<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: [August 7, 2024, 7:48pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/8 "2024-08-07T19:48:32Z")

</div>

> [@rafael.guerra](#):
>
> it seems nicer to write it like this:
> 
> ```julia
> for (i, str) in pairs(strvec)
> 
> ```

Technically, I would recommend `enumerate` rather than `pairs` here, since `i` is used as an index for a `Matrix`, to allow `strvec` to be an arbitrary collection (possibly not 1-based, or possibly an iterator).

---

<div class="post-metadata">

### Author: ![mohamed.d180](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed.d180/32/52028_2.png) [@mohamed.d180](https://discourse.julialang.org/u/mohamed.d180)
#### Post date: [August 7, 2024, 8:01pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/9 "2024-08-07T20:01:04Z")

</div>

We can also for variety use :

```julia
split_vec(s) = stack([[SubString(x, 1:2),
            SubString(x, 3:3) ,
            SubString(x, 4)] for x in s], dims=1)

```

```julia
julia> @benchmark split_vec(strvec)
BenchmarkTools.Trial: 10000 samples with 10 evaluations.
 Range (min … max): 1.710 μs … 30.801 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 1.947 μs ┊ GC (median): 0.00%
 Time (mean ± σ): 1.994 μs ± 610.776 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

     ▆ ▁▃█▁                                                   
  ▃▃▄██▇████▅▃▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▁▂▁▂▂▂▂▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
  1.71 μs Histogram: frequency by time 3.68 μs <

 Memory estimate: 736 bytes, allocs estimate: 5.

```

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [August 8, 2024, 1:20pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/10 "2024-08-08T13:20:40Z")

</div>

> [@mohamed.d180](#):
>
> ```julia
> split_vec(s) = stack([[SubString(x, 1:2),
> SubString(x, 3:3) ,
> SubString(x, 4)] for x in s], dims=1)
> 
> ```

FYI, this variant seems to be twice as fast if we can avoid applying `permutedims()` to the result:

```julia
split_vec3(s) = stack((SubString(x, 1:2), SubString(x, 3:3), SubString(x, 4)) for x in s)

```

---

<div class="post-metadata">

### Author: ![mohamed.d180](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed.d180/32/52028_2.png) [@mohamed.d180](https://discourse.julialang.org/u/mohamed.d180)
#### Post date: [August 8, 2024, 1:27pm UTC](https://discourse.julialang.org/t/optimize-splitting-vector-of-strings/117924/11 "2024-08-08T13:27:50Z")

</div>

That is true

> this variant seems to be twice as fast

But the the required matrix will be like this

```julia
julia> split_vec3(strvec)
3×3 Matrix{SubString{String}}:
 "AA" "BB" "CC"
 " " "C" "M"
 "entryA" " entryB" " entryC"

```

Which is the transpose of the answer .

I think using generators was behind that speed , see this

```julia
julia> split_vec(s) = stack(((SubString(x, 1:2),
                   SubString(x, 3:3) ,
                   SubString(x, 4)) for x in s), dims=1)
split_vec (generic function with 1 method)

julia> @benchmark split_vec(strvec)
BenchmarkTools.Trial: 10000 samples with 84 evaluations.
 Range (min … max): 834.476 ns … 4.861 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 913.095 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 922.723 ns ± 106.815 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

                  ▁█▅▄▃                                          
  ▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▂█████▇▃▂▂▂▂▂▂▂▂▂▁▂▂▂▂▂▁▂▁▂▂▁▂▂▂▁▂▂▂▂▂▂▂▂▂▂▂▂▂ ▃
  834 ns Histogram: frequency by time 1.09 μs <

 Memory estimate: 272 bytes, allocs estimate: 1.

```

And here is a better version using `map`

```julia
split_vec4(s) = map(x -> SubString.(x, (1:2, 3:3, 4)), s)

julia> @benchmark split_vec4(strvec)
BenchmarkTools.Trial: 10000 samples with 196 evaluations.
 Range (min … max): 472.806 ns … 2.811 μs ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 518.617 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 521.972 ns ± 48.326 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

                         ▃█▃                                    
  ▂▂▂▁▂▁▁▁▁▁▁▁▁▁▂▁▁▁▁▁▂▂▅███▅▄▂▂▂▂▂▂▂▂▂▁▁▁▁▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂ ▂
  473 ns Histogram: frequency by time 584 ns <

 Memory estimate: 272 bytes, allocs estimate: 1.

```
