2

I have a text file that looks like:

1 aaaa
2 bbbb
3 cccc
4 dddd
2 eeee
2 ffff
4 gggg

I would like to map these into some sort of associative array so that I can access, for example, all the values associated with the key 2 and all the values associated with the key 4, etc.:

1->aaaa
2->bbbb,eeee,ffff
3->cccc
4->dddd,gggg

I haven't been able to figure out how to do this with 'declare -A MYMAP'. Is there some easy way to do this?

--------update--------

my key/value pairs look like this actually:

bb126.B1 bb126.1.ms.01
bb126.B2 bb126.1.ms.02
bb126.B3 bb126.1.ms.03
bb126.B4 bb126.1.ms.04
whoan
  • 8,143
  • 4
  • 39
  • 48
  • What is the exact error? – Maria Ines Parnisari Jan 08 '15 at 03:33
  • @l19 Well, I only know how to map one value to one key with declare MYMAP. How do I map multiple values to one key? –  Jan 08 '15 at 03:36
  • What do you need to do with the values later? Do you need to be able to get at them individually or just as one large string? – Etan Reisner Jan 08 '15 at 03:37
  • I have another file with a subset of the keys. I'm going to iterate over those keys in the other file and replace them with their sets of associated values (comma delimited). –  Jan 08 '15 at 03:41
  • Do the values ever contain whitespace? – John1024 Jan 08 '15 at 03:50
  • No, they look like this: bb135.B1. And values look like: bb135.1.ms.15. There are multiple values for each key (bb135.1.ms.15, bb135.9.ms.15, ...) –  Jan 08 '15 at 03:52

2 Answers2

4

Here's a solution with Shell Parameter Expansion and Associative Arrays:

# store
declare -A array # this is the only update
while read key value; do
    array[$key]="${array[$key]}${array[$key]:+,}$value"
done < file
# print
for key in "${!array[@]}"; do echo "$key->${array[$key]}"; done

Explanation

array[$key]="${array[$key]}${array[$key]:+,}$value"

saves each $value in array[$key] separated by ,:

  • ${array[$key]} save previous value(s) (if any).
  • ${array[$key]:+,} adds a , if there's a previous value.
  • $value adds the new read value.

for key in "${!array[@]}"; do echo "$key->${array[$key]}"; done

prints the values associated to each $key.


From man bash:

${parameter:+word}
If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

${!name[@]}
${!name[*]}
If name is an array variable, expands to the list of array indices (keys) assigned in name. If name is not an array, expands to 0 if name is set and null otherwise. When ‘@’ is used and the expansion appears within double quotes, each key expands to a separate word.


Example

$ cat file
1 aaaa
2 bbbb
3 cccc
4 dddd
2 eeee
2 ffff
4 gggg

$ ./script.sh 
1->aaaa
2->bbbb,eeee,ffff
3->cccc
4->dddd,gggg
whoan
  • 8,143
  • 4
  • 39
  • 48
-2

The below script is for comma separated value, you can change as per your need

awk -F "," '{OFS=","} 1 {if (a[$1]) {a[$1] = a[$1]" "$2} else {a[$1] = $2}} END {for (i in a)  { print i,a[i]}}'  input_file > Output_file
Aivan Monceller
  • 4,636
  • 10
  • 42
  • 69
Viju
  • 1