2

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.

1
  • 2
    From - mywiki.wooledge.org/BashGuide/Arrays. The order of the keys you get back from an associative array using the "${!array[@]}" syntax is unpredictable; it won't necessarily be the order in which you assigned elements, or any kind of sorted order. Associative arrays are not well suited to storing lists that need to be processed in a specific order. Commented Dec 12, 2018 at 10:43

1 Answer 1

3

Iteration Order

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

Unique Prefixes of Keys

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.