Inverting an associative array
Let's say I have an associative array in bash
,
declare -A hash
hash=(
["foo"]=aa
["bar"]=bb
["baz"]=aa
["quux"]=bb
["wibble"]=cc
["wobble"]=aa
)
where both keys and values are unknown to me (the actual data is read from external sources).
How may I create an array of the keys corresponding to the same value, so that I may, in a loop over all unique values, do
printf 'Value "%s" is present with the following keys: %sn' "$value" "${keys[*]}"
and get the output (not necessarily in this order)
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
The important bit is that the keys are stored as separate elements in the keys
array and that they therefore do not need to be parsed out of a text string.
I could do something like
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: %sn'
"$value" "${keys[*]}"
seen[$value]=1
done
But it seems a bit inefficient with that double loop.
Is there a piece of array syntax that I've missed for bash
?
Would doing this in e.g. zsh
give me access to more powerful array manipulation tools?
In Perl, I would do
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: %sn",
$value, join( " ", @{ $keys{$value} } ) );
}
But bash
associative arrays can't hold arrays...
I'd also be interested in any old school solution possibly using some form of indirect indexing (building a set of index array(s) when reading the values that I said I had in hash
above?). It feels like there ought to be a way to do this in linear time.
bash scripting zsh associative-array
add a comment |
Let's say I have an associative array in bash
,
declare -A hash
hash=(
["foo"]=aa
["bar"]=bb
["baz"]=aa
["quux"]=bb
["wibble"]=cc
["wobble"]=aa
)
where both keys and values are unknown to me (the actual data is read from external sources).
How may I create an array of the keys corresponding to the same value, so that I may, in a loop over all unique values, do
printf 'Value "%s" is present with the following keys: %sn' "$value" "${keys[*]}"
and get the output (not necessarily in this order)
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
The important bit is that the keys are stored as separate elements in the keys
array and that they therefore do not need to be parsed out of a text string.
I could do something like
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: %sn'
"$value" "${keys[*]}"
seen[$value]=1
done
But it seems a bit inefficient with that double loop.
Is there a piece of array syntax that I've missed for bash
?
Would doing this in e.g. zsh
give me access to more powerful array manipulation tools?
In Perl, I would do
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: %sn",
$value, join( " ", @{ $keys{$value} } ) );
}
But bash
associative arrays can't hold arrays...
I'd also be interested in any old school solution possibly using some form of indirect indexing (building a set of index array(s) when reading the values that I said I had in hash
above?). It feels like there ought to be a way to do this in linear time.
bash scripting zsh associative-array
add a comment |
Let's say I have an associative array in bash
,
declare -A hash
hash=(
["foo"]=aa
["bar"]=bb
["baz"]=aa
["quux"]=bb
["wibble"]=cc
["wobble"]=aa
)
where both keys and values are unknown to me (the actual data is read from external sources).
How may I create an array of the keys corresponding to the same value, so that I may, in a loop over all unique values, do
printf 'Value "%s" is present with the following keys: %sn' "$value" "${keys[*]}"
and get the output (not necessarily in this order)
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
The important bit is that the keys are stored as separate elements in the keys
array and that they therefore do not need to be parsed out of a text string.
I could do something like
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: %sn'
"$value" "${keys[*]}"
seen[$value]=1
done
But it seems a bit inefficient with that double loop.
Is there a piece of array syntax that I've missed for bash
?
Would doing this in e.g. zsh
give me access to more powerful array manipulation tools?
In Perl, I would do
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: %sn",
$value, join( " ", @{ $keys{$value} } ) );
}
But bash
associative arrays can't hold arrays...
I'd also be interested in any old school solution possibly using some form of indirect indexing (building a set of index array(s) when reading the values that I said I had in hash
above?). It feels like there ought to be a way to do this in linear time.
bash scripting zsh associative-array
Let's say I have an associative array in bash
,
declare -A hash
hash=(
["foo"]=aa
["bar"]=bb
["baz"]=aa
["quux"]=bb
["wibble"]=cc
["wobble"]=aa
)
where both keys and values are unknown to me (the actual data is read from external sources).
How may I create an array of the keys corresponding to the same value, so that I may, in a loop over all unique values, do
printf 'Value "%s" is present with the following keys: %sn' "$value" "${keys[*]}"
and get the output (not necessarily in this order)
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
The important bit is that the keys are stored as separate elements in the keys
array and that they therefore do not need to be parsed out of a text string.
I could do something like
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: %sn'
"$value" "${keys[*]}"
seen[$value]=1
done
But it seems a bit inefficient with that double loop.
Is there a piece of array syntax that I've missed for bash
?
Would doing this in e.g. zsh
give me access to more powerful array manipulation tools?
In Perl, I would do
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: %sn",
$value, join( " ", @{ $keys{$value} } ) );
}
But bash
associative arrays can't hold arrays...
I'd also be interested in any old school solution possibly using some form of indirect indexing (building a set of index array(s) when reading the values that I said I had in hash
above?). It feels like there ought to be a way to do this in linear time.
bash scripting zsh associative-array
bash scripting zsh associative-array
edited 59 mins ago
Kusalananda
asked 1 hour ago
KusalanandaKusalananda
136k17256424
136k17256424
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f506891%2finverting-an-associative-array%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f506891%2finverting-an-associative-array%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown