Reputation: 5714
I have two problems handling associative arrays. First one is that I can't keep a custom order on it.
#!/bin/bash
#First part, I just want to print it ordered in the custom created order (non-alphabetical)
declare -gA array
array["PREFIX_THIS","value"]="true"
array["PREFIX_IS","value"]="false"
array["PREFIX_AN","value"]="true"
array["PREFIX_ORDERED","value"]="true"
array["PREFIX_ARRAY","value"]="true"
for item in "${!array[@]}"; do
echo "${item}"
done
Desired output is:
PREFIX_THIS,value
PREFIX_IS,value
PREFIX_AN,value
PREFIX_ORDERED,value
PREFIX_ARRAY,value
But I'm obtaining this:
PREFIX_IS,value
PREFIX_ORDERED,value
PREFIX_THIS,value
PREFIX_AN,value
PREFIX_ARRAY,value
Until here the first problem. For the second problem, the order is not important. I added more stuff to the associative array and I just want to loop on it without duplicates. Adding this:
array["PREFIX_THIS","text"]="Text for the var"
array["PREFIX_IS","text"]="Another text"
array["PREFIX_AN","text"]="Text doesn't really matter"
array["PREFIX_ORDERED","text"]="Whatever"
array["PREFIX_ARRAY","text"]="More text"
I just want to loop over "PREFIX_THIS", "PREFIX_IS", "PREFIX_AN", etc... printing each one only once. I just want to print doing an "echo" on loop (order is not important for this part, just to print each one only once). Desired output:
PREFIX_ORDERED
PREFIX_AN
PREFIX_ARRAY
PREFIX_IS
PREFIX_THIS
I achieved it doing "dirty" stuff. But there must be a more elegant way. This is my working but not too much elegant approach:
already_set=""
var_name=""
for item in "${!array[@]}"; do
var_name="${item%,*}"
if [[ ! ${already_set} =~ "${var_name}" ]]; then
echo "${var_name}"
already_set+="${item}"
fi
done
Any help? Thanks.
Upvotes: 2
Views: 2610
Reputation: 27215
As Inian pointed out in the comments, you cannot fix the order in which "${!array[@]}"
expands for associative arrays. However, you can store all keys inside a normal array that you can order manually.
keysInCustomOrder=(PREFIX_{THIS,IS,AN,ORDERED,ARRAY})
for key in "${keysInCustomOrder[@]}"; do
echo "do something with ${array[$key,value]}"
done
For your second problem: a["key1","key2"]
is the same as a["key1,key2"]
. In bash, arrays are always 1D therefore there is no perfect solution. However, you can use the following one-liner as long as ,
is never part of key1
.
$ declare -A array=([a,1]=x [a,2]=y [b,1]=z [c,1]=u [c,2]=v)
$ printf %s\\n "${!array[@]}" | cut -d, -f1 | sort -u
a
b
c
When your keys may also contain linebreaks delemit each key by null \0
.
printf %s\\0 "${!array[@]}" | cut -zd, -f1 | sort -zu
Alternatively you could use reference variables to simulate 2D-arrays, however I would advice against using them.
Upvotes: 2