Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: pointers and associative maps



Slurping in the whole thread here ...

On Feb 27,  1:09pm, Jaromil wrote:
}
} I'm puzzled by a problem I encounter using pointers and associative
} maps. I want to use a variable as pointer for an associative map, then
} iterate through the map to get all its values, for saving it to a file
} and implement a simple load/save key/value store.

The root of some of this confusion may be that zsh doesn't actually have
"pointers".  With a few special exceptions variables are always resolved
to a value as early as possible and thereafter the value is what is
passed around and manipulated by parameter flags etc.

Furthermore, fundamentally zsh has only two kinds of values:  Scalars
and arrays.  Associative arrays are always resolved to one of those
two things -- the scalar at a particular key, the array of all the
keys, the array of all the values, the array of alternating keys and
values, etc.

The (P) flag gives you exactly one level of indirection; "take this
value as a name and resolve it to the value at that name before any
further processing."  It doesn't give you a handle to the thing whose
value is resolved.  Some of the other flags like (k) and (v) are used
at the same level as (P) so that (Pk) gives you the keys of a named
array; other flags are applied later, all depending on the order of
the expansion rules described in the manual.

Thus you can't use (P) on the name of an associative array to get a
thing that still behaves like an associative array.  You already dealt
with that particular detail by iterating on a numeric index instead of
using the keys, so perhaps all the foregoing is just background for
other interested readers.


On Feb 27,  1:46pm, Jaromil wrote:
}
} solved! using ${(Pv)${_map}[$c]}

Sadly, no.  As you later discovered, the above only "works" because
(unless KSH_ARRAYS) the value of ${hash} is the same as the value of
${(v)hash}.

You did in fact want ${${(Pv)_map}[$c]} all along, see below.


On Feb 27,  3:02pm, Jaromil wrote:
}
} puzzling enough, after running the function one can do:
} 
} print ${${(Pk)_map}[$c]}
} 
} please note that having the (Pk) modifier in the inner brackets when
} run inside the function does not work at all, rather indexes single
} chars in the key/value retrieved (as mentioned in my first post)

That's a quoting issue.  ${${(Pk)_map}[$c]} and "${${(Pk)_map}[$c]}"
are not the same thing; adding the double quotes forces the value to
be interpreted as a scalar instead of an array, so the subcript [$c]
indexes into the scalar string instead of into the array.

You can use "${${(Pk@)_map}[$c]}" to force the index to use the array
rather than the scalar, or (depending on context) you can remove the
double quotes as you did at the shell prompt.

The formulation ${(Pk)${_map}[$c]} first gets the array of values for
${(P)${_map}} and then gives you the key at index [$c], which because
of the conversion to a plain array is just $c back again.  Any other
nesting will either attach (k) to ${_map} or separate (k) from one of
(P) or [$c], and thereby produce a different result.

% c=2
% print ${(Pk)${_map}[$c]} ${(k)${(P)_map}[$c]} ${${(Pk)_map}[$c]}
2 value2 key2

Some other formulations may leave you scratching your head until you
realize that (v) and (k) are no-ops on scalars and [$c] has already
reduced the result to a scalar.

One other tidbit - given:

    typeset -A hash
    hash=(key1 value1 key2 value2)
    print ${(k)hash}
    print ${(v)hash}

Here the keys and values are guaranteed to come out in corresponding
sequence, but might come out in a different order than added:

    key2 key1
    value2 value1

However, given:

    print ${(k)hash}
    hash+=(key3 value3)
    print ${(v)hash}

You *might* get e.g.:

    key2 key1
    value1 value3 value2

That is, the order of old keys/values is not guaranteed to stay the same
after new keys/values are added.

-- 
Barton E. Schaefer



Messages sorted by: Reverse Date, Date, Thread, Author