Reputation: 2836
I am trying to create an associative array of associative arrays in gawk, and what I initially tried was:
options[key][subkey] = 1
However, when it got to this line, I unceremoniously received the error fatal: attempt to use scalar 'option["Declaration"]' as an array
("Declaration" being one of the main keys that my program uses, although I presume the exact value is irrelevant. At this particular point in the program, there was no "Declaration" entry assigned, although there were entries which had "Declaration" as a subkey on other entries, which may be meaningful).
So with a bit of googling, I found another stackoverflow question that looked like it answered my issue, so I put the following code immediately above it:
if (typeof(options[key])!="array") {
options[key] = 0;
delete options[key];
split("",options[key]);
}
However, this does not work either, instead now giving me the error: fatal: split: second argument is not an array
What am I doing wrong?
EDIT: Note, that I cannot use a basic 2-dimensional array here... for what I am doing, it is important that I am using one associative array to another because I need to be able to later identify the subkeys that were used on a given key.
Pursuant to requests below, I am posting the relevant functions that use the associative array, which may help clarify what is going on.
function add_concrete(key, concrete) {
if (key == concrete) {
return;
}
if (length(options[key])>0) {
for(i in options[key]) {
add_concrete(i, concrete);
}
}
contains[key][concrete] = 1
}
function add_options(name, value) {
subkey = trim(name);
if (subkey == "") {
return;
}
if (match(value, ";") > 0) {
exporting = 0;
}
split(value, args, /[ |;]*/);
for (i in args) {
key = trim(args[i]);
if (key != "") {
print("Adding " name " to " key);
options[key][subkey] = 1
if (concrete[key]) {
add_concrete(subkey, key);
}
}
}
}
Upvotes: 0
Views: 130
Reputation: 2875
Don't use delete ……
it's so brute force
Use a dummy variable for a soft init :
for (_ in options[key]) {
break
}
This way you can guarantee options[key]
is now a sub-array, while preserving any pre-existing values it might already have.
With this approach, if you're very certain options[key]
could only be a sub-array, then you can skip all the checks for typeof( )
or isarray( )
.
The instant break
also ensures it spends practically zero amount of time in the dummy iterator.
If you need a unified function to calculate array length()
that's portable while leveraging built-in length(arr)
of select awk
variants, here's what I have in my own library :
function lengthA(__, _, ___) {
for (_ in __)
if (_ = "\x6" < "x\6") # gawk --posix (-P) mode detector
return length(__)
else
break
for (___ in __)
_++
return +_
}
lengthA( )
is a fully POSIX
-compliant awk
function that has no semi colons or braces anywhere (other than the mandatory pair enclosing the function). awk
's syntax is surprisingly modern looking for a 47-year old language.
The utter lack of types in awk
is a godsend. Just within the same function, the temp variable _
performed 3 different roles without the need to explicitly recast during any transition phases :
iterator
Upvotes: 0
Reputation: 37424
Sorry, cooking at the same time. As you didn't post much, don't have much to work with, but with no "initialization":
$ awk 'BEGIN {
options[key] = 0;
delete options[key];
# options[key][1] # cant see me
split("",options[key]);
}'
awk: cmd. line:5: fatal: split: second argument is not an array
But with "initialization":
$ awk 'BEGIN {
options[key] = 0;
delete options[key];
options[key][1] # can see me
split("",options[key]);
}'
$_ # see this cursor happily blinking without any error
Upvotes: 2