[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
>
>
>