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