Associative arrays (Bash): verschil tussen versies
(→Awk) |
|||
Regel 12: | Regel 12: | ||
</pre> | </pre> | ||
− | == | + | == There are no multidimensional arrays == |
Associative arrays aren't really multidimensional arrays, they only emulate them. As an example: | Associative arrays aren't really multidimensional arrays, they only emulate them. As an example: |
Versie van 29 sep 2022 09:55
- Associative arrays are arrays where you can give elements their own name
- You can use associative arrays to mimic multi-dimensional arrays, with emphasize on mimic
- Associative arrays are new in Bash 4. To verify which version of Bash you have:
bash --version
An associative array means, that the index doesn't have to be a number, but can be symbolic, or a key. E.g.:
declare -A j j[fruit]=apple j[color]=blue
There are no multidimensional arrays
Associative arrays aren't really multidimensional arrays, they only emulate them. As an example:
unset j declare -A j j[0,0]="00" j[0,1]="01" j[0, 1]="0 1" for i in "${!j[@]}" do echo "Index: $i - Value: ${j[$i]}" done
Output:
Index: 0, 1 - Value: 0 1 Index: 0,1 - Value: 01 Index: 0,0 - Value: 00
So, the entry with index [0, 1]
, is not the same as with index [0,1]
. This shows that the whole index is used as one index. Not as something multidimensional.
But does this actually matter? You can include variables for these indices, and I don't really need to make calculations concerning different dimensions.
Number of rows or columns?
A problem with this 'emulated' multi-dimensional arrays: You can't read-out the number of rows or columns, for there are no real rows and columns. Illustration:
# The array below is 3x2 # unset j declare -A j j[1,1]="11" j[1,2]="12" j[2,1]="21" j[2,2]="22" j[3,1]="31" j[3,2]="32" echo "Length: ${#j[@]}" echo "Complete array: ${j[@]}"
Output:
Length: 6 Complete array: 21 22 31 31 12 11
This can be a problem, when you want to loop over the rows - Can't do that.
Additionally, the syntax with #
for reading out the length of an array, illustrates that arrays are basically one-dimensional.
Iterate over rows?
If there is not really such a thing as rows and columns, than how to iterate over them?
That's probably not so difficult, Just remember that the 'multidimensional index' is just one index, and that you can iterate over it. E.g.:
for i in "${!imwiz[@]}" do echo "Index: $i" echo "Value: ${imwiz[$i]}" done
Retrieve a specific value?
How to retrieve a specific value? I suspect that isn't that hard either, and goes similarly as iterating over the array
Solutions
- When arrays have a numerical index, always start with the same number ⇒ I prefer base 1, just as in matrix algebra
- For two-dimensional arrays, the first dimensions is always rows (x) and the second is always columns (y) - Just as in matrix algebra
- Don't use spaces around the
,
that separates indices: You need a uniform syntax, and using spaces actually messes up language highlighting in Sublime Text - Store the dimensions in associated variables (when needed). E.g., in the example above:
j_rows=3
andj_columns=2
Examples
As stated above, these are not really multidimensional arrays, just arrays with fancy indices. It doesn't matter if these indices are numerical or symbolic:
declare -A j j[0,0,0]="000" j[0,0,1]="001" j[0,1,0]="010" j[0,1,1]="011" j[1,0,0]="100" j[1,0,1]="101" j[1,1,0]="110" j[1,1,1]="111" echo "${j[0,0,0]} ${j[0,0,1]} ${j[0,1,0]} ${j[0,1,1]}" echo "${j[1,0,0]} ${j[1,0,1]} ${j[1,1,0]} ${j[1,1,1]}"
unset j declare -A j j[fruit,one]=Mango j[fruit,two]=Apple j[bird,1]=Cockatail j[bird,2]=Spottingbird j[flower,1]=Rose j[flower,2]=Sunflower j[animal]=Tiger for i in "${j[@]}" do echo "Entry: $i" done
Output:
Entry: Cockatail Entry: Spottingbird Entry: Rose Entry: Sunflower Entry: Tiger Entry: Apple Entry: Mango
Note that the entries seem to appear in arbitrary order
Loop through an array
Again: These are not multidimensional arrays. They only seem that way.....
This works [1]:
declare -A j j[fruit]=Mango j[bird]=Cockatail j[flower]=Rose j[animal]=Tiger for i in "${j[@]}" do echo "Entry: $i" done
Output:
Entry: Mango Entry: Rose Entry: Tiger Entry: Cockatail
This works:
declare -A j j[fruit,1]=Mango j[fruit,2]=Apple j[bird,1]=Cockatail j[bird,2]=Spottingbird j[flower,1]=Rose j[flower,2]=Sunflower j[animal,1]=Tiger j[animal,1]=Mouse for i in "${j[@]}" do echo "Entry: $i" done
Output:
Entry: Cockatail Entry: Spottingbird Entry: Rose Entry: Sunflower Entry: Mouse Entry: Mango Entry: Apple
The only problem: The entries seem to be quite random. This is also the case if I insert statement unset assArray1
at the beginning of the script.
Looping through the rows of an associate array: This one isn't as cool as the code before, because the index is given explicitly:
i=1 for ((i; i<=$number_of_sites; i++)) do echo "Row ${i}: ${site[$i,1]} & ${site[$i,2]}" done
Loop through the index of an array
Use the symbol !
to refer to an array's index, rather than its content:
declare -A j j[fruit,1]=Mango j[fruit,2]=Apple j[bird,1]=Cockatail j[bird,2]=Spottingbird j[flower,1]=Rose j[flower,2]=Sunflower j[animal,1]=Tiger j[animal,1]=Mouse for i in "${!j[@]}" do echo "Index: $i" done
With output:
Index: bird,1 Index: bird,2 Index: flower,1 Index: flower,2 Index: animal,1 Index: fruit,1 Index: fruit,2
However, this is totally not exciting: The index was explicitly specified when initialising the array. That's different when you initialise an array through e.g., i= ( 1 2 3 blub 5 )
(or whatever the exact syntax is).
Index + value
Again, not very exciting, but maybe instructive at times:
unset j declare -A j j[fruit,one]=Mango j[fruit,two]=Apple j[bird,1]=Cockatail j[bird,2]=Spottingbird j[flower,1]=Rose j[flower,2]=Sunflower j[animal]=Tiger for i in "${!j[@]}" do echo "Index: $i - Value: ${j[$i]}" done
Output:
Index: bird,1 - Value: Cockatail Index: bird,2 - Value: Spottingbird Index: flower,1 - Value: Rose Index: flower,2 - Value: Sunflower Index: animal - Value: Tiger Index: fruit,two - Value: Apple Index: fruit,one - Value: Mango
Length of an array
Use the symbol #
to retrieve the length of an array. Since associative arrays are just vectors after all, there is only one dimension to retrieve.
Example:
unset j declare -A j j[0,0]="00" j[0,1]="01" j[1,0]="10" j[1,1]="11" j[2,0]="20" j[2,1]="21" echo "Length: ${#j[@]}"
Output:
Length: 6
Awk
And for something entirely else: I kinda move from spreadsheets to associative arrays and back. A while ago I saw on YouTube Gary Explains: EVERYONE Needs to Learn a Little Bit of AWK! - Maybe this is what I have been looking?