Angenommen, ich habe ein assoziatives Array in bash
,
declare -A hash
hash=(
["foo"]=aa
["bar"]=bb
["baz"]=aa
["quux"]=bb
["wibble"]=cc
["wobble"]=aa
)
wo mir sowohl Schlüssel als auch Werte unbekannt sind (die tatsächlichen Daten werden aus externen Quellen gelesen).
Wie kann ich ein Array der Schlüssel erstellen, die demselben Wert entsprechen, damit ich dies in einer Schleife über alle eindeutigen Werte tun kann?
printf 'Value "%s" is present with the following keys: %s\n' "$value" "${keys[*]}"
und erhalten Sie die Ausgabe (nicht unbedingt in dieser Reihenfolge)
Value "aa" is present with the following keys: foo baz wobble
Value "bb" is present with the following keys: bar quux
Value "cc" is present with the following keys: wibble
Das wichtige Bit ist, dass die Schlüssel als separate Elemente im keys
Array gespeichert sind und daher nicht aus einer Textzeichenfolge analysiert werden müssen.
Ich könnte so etwas tun
declare -A seen
seen=()
for value in "${hash[@]}"; do
if [ -n "${seen[$value]}" ]; then
continue
fi
keys=()
for key in "${!hash[@]}"; do
if [ "${hash[$key]}" = "$value" ]; then
keys+=( "$key" )
fi
done
printf 'Value "%s" is present with the following keys: %s\n' \
"$value" "${keys[*]}"
seen[$value]=1
done
Aber es scheint ein bisschen ineffizient mit dieser Doppelschleife.
Gibt es eine Array-Syntax, die ich verpasst habe bash
?
Würde zsh
mir dies beispielsweise Zugriff auf leistungsfähigere Array-Manipulationswerkzeuge geben?
In Perl würde ich tun
my %hash = (
'foo' => 'aa',
'bar' => 'bb',
'baz' => 'aa',
'quux' => 'bb',
'wibble' => 'cc',
'wobble' => 'aa'
);
my %keys;
while ( my ( $key, $value ) = each(%hash) ) {
push( @{ $keys{$value} }, $key );
}
foreach my $value ( keys(%keys) ) {
printf( "Value \"%s\" is present with the following keys: %s\n",
$value, join( " ", @{ $keys{$value} } ) );
}
Aber bash
assoziative Arrays können keine Arrays enthalten ...
Ich würde mich auch für eine Old-School-Lösung interessieren, die möglicherweise eine Form der indirekten Indizierung verwendet (Erstellen einer Reihe von Indexarrays beim Lesen der Werte, die ich hash
oben angegeben habe?). Es scheint, dass es einen Weg geben sollte, dies in linearer Zeit zu tun.
seen
(im Echo) sollte seinelements
. Ich nehme jedoch an, dass jedes $ {Seen [$ k]} eine Zeichenfolge mit durch Leerzeichen getrennten Elementen ist, für die daher eine zusätzliche Analyse erforderlich ist, die das OP nicht wollte (?)