Find key that matches value in zsh associative array?

Viewed 473

In a regular array, I can use (i) or (I) to search for the index of entries matching a given value (first match from the start or end of the array, respectively):

list=(foo bar baz)
echo $list[(i)bar]
# => 2

This doesn't work for associative arrays, to get (one of) the key(s) where a value is found:

declare -A hash=([foo]=bar [baz]=zoo)
echo $hash[(i)bar]
# => no output 

Is there another mechanism for doing this, other than manually looping through?

2 Answers

The (r) subscript flag combined with the (k) parameter flag should give you what you want:

declare -A hash=([foo]=bar [baz]=zoo)
echo ${(k)hash[(r)bar]}
# => foo

The man page section on the (r) subscript flag only talks about returning values and ignores this usage, so it's hard to find.

Here is something completely disgusting:

% declare -A hash=([foo]=bar [baz]=zoo)
% echo ${${(kA)hash}[${${(A)hash[@]}[(i)bar]}]}
foo

Basically, it consists of two parts:

  1. ${${(A)hash[@]}[(i)bar]}, which computes the index of bar in an anonymous array consisting of the values of the associative array.
  2. ${${(kA)hash}[...]}, which indexes the anonymous array consisting of the keys of the associative array using the numerical index computed by the previous expansion.

I'm not aware of a short equivalent to the I flag, and I too am surprised that the seemingly obvious extension to associative arrays doesn't exist.

Related