1

In Bash, given an associative array, how do I find the length of the longest key?

Say, I declare myArray as shown below:

$  declare -A myArray=([zero]=nothing [one]='just one' [multiple]='many many')
$  echo ${myArray[zero]}
nothing
$  echo ${myArray[one]}
just one
$  echo ${myArray[multiple]}
many many
$

I can get it using the below one-liner

$  vSpacePad=`for keys in "${!myArray[@]}"; do echo $keys; done | awk '{print length, $0}' | sort -nr | head -1 | awk '{print $1}'`;
$  echo $vSpacePad
8
$

Am looking for something simpler like below, but unfortunately, these just give the count of items in the array.

$  echo "${#myArray[@]}"
3
$  echo "${#myArray[*]}"
3
vtbr
  • 13
  • 3

2 Answers2

7

You do need to loop over the keys, but you don't need any external tools:

max=-1
for key in "${!myArray[@]}"; do
  len=${#key}
  ((len > max)) && max=$len
done
echo $max    # => 8

If you want to print the elements of an array one per line, you don't need a loop: printf is your friend:

printf '%s\n' "${!myArray[@]}"

printf iterates until all the arguments are consumed

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • This still needs loop. I wanted to avoid for-loop. Thanks for the tip on `printf` – vtbr Apr 22 '21 at 14:40
  • 1
    @vtbr You have to choose between ***fork*** or ***loop***! Depending on number of elements in your array, with small array, ***loop*** is quicker than ***fork***!! (Note: `maxlen=$(printf "%s\n" "${!array[@]}" | wc -L)` implie at least 2 forks! – F. Hauri - Give Up GitHub Apr 22 '21 at 15:32
1

Is there a built-in way to get the maximum length of the keys in an associative array

No.

how do I find the length of the longest key?

Iterate over array elements, get the element length and keep the biggest number.

Do not use backticks `. Use $(..) instead.

Quote variable expansions - don't echo $keys, do echo "$keys". Prefer printf to echo.

If array elements do not have newlines and other fishy characters, you could:

printf "%s\n" "${myArray[@]}" | wc -L
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • My one-liner size was reduced considerably using your `printf` and `wc` combination. I am going to use this. Though, I'll have to do it for keys `"${!myArray[@]}"`. – vtbr Apr 22 '21 at 14:44
  • Length in byte of length in char? `printf "A\342\226\200b\n" | LANG=C wc -L` -> `2`, but `printf "A\342\226\200b\n" | LANG=en_US.utf8 wc -L` -> `3`!! See [Length of string in bash](https://stackoverflow.com/a/31009961/1765658) – F. Hauri - Give Up GitHub Apr 22 '21 at 15:27
  • `Length in byte of length in char?` Well, it's not only utf-8, wc also handled tabs (`printf "\t\n" | wc -L` -> 8) and CR (`printf "123\r123\n" | wc -L` = 3) and similar. – KamilCuk Apr 22 '21 at 16:14