help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Fastest way to join an array into a string


From: João Eiras
Subject: Re: [Help-bash] Fastest way to join an array into a string
Date: Tue, 27 Aug 2019 11:04:20 +0200

This is the snippet I use

# @param ARRAYNAME
# @param separator
function array_join {
  local arrexpr="$1[*]"
  if [[ ${#2} -le 1  ]]; then
    local IFS="$2"
    printf %s "${!arrexpr}"
  else
    local IFS=$'\x01'
    local res="${!arrexpr}"
    printf %s ${res//$IFS/$2}
  fi
}

# test
x=(1 2 3 4 5 1 2 3 4 5 1 2)
array_join x --

The advantage is that it does the least amount of explicit string
operations and relies on bash's buitin operators. I had a version with a
loop for the case where the separator is bigger than 1 character, but I
just benchmarked that one and it is 4X slower than just using ${array[*]}

Cheers.


On Tue, 27 Aug 2019 at 07:50, Stephane Chazelas <address@hidden>
wrote:

> 2019-08-26 13:47:36 -0500, Peng Yu:
> [...]
> >             echo -n "$1"
>
> You can't use echo for arbitrary data. Depending on the
> environment and how bash was built, that will either
> - output that -n
> - fail if $1 is -n, -E, -e or any combination like -neEneE
> - fail if $1 contains backslashes
>
> Use printf again: printf %s "$1"
>
> >             shift
>
> You'll get an error if $@ is the empty list (no argument).
>
> >             if (($#)); then
> >                 declare x
>
> Why "declare x"
>
> >                 printf "${separator//%/%%}%s" "$@"
> [...]
>
> You also need to escape \. You're also missing the newline
> delimiter.
>
> Note that if you're printing it, that means that if you need to
> store it in a variable, you'll need to use command substitution,
> which involves running an extra process and writing/reading the
> data through a pipe.
>
> Even if you use printf -v, like in:
>
> join_into() {
>   local -n _var="$1"
>   local _sep="$2"
>   shift 2
>   if (($# > 1)); then
>     sep=${sep//%/%}
>     sep=${sep//\\/\\\\}
>     printf -v _var "${separator//%/%%}%s" "${@:2}"
>     _var=$1$_var
>   else
>     _var=$1
>   fi
> }
>
> I find it's still orders of magnitude slower than the approach that uses
> ${*/#/$sep}.
>
> On my system, it is significantly slower than invoking perl or python
>
> like
>
> result=$(perl -le 'print join shift, @ARGV' -- sep "$@")
>
> or
>
> result=$(python -c 'import sys; print(sys.argv[1].join(sys.argv[2:]))' sep
> "$@")
>
> --
> Stephane
>
>
>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]