zsh-users
 help / color / mirror / code / Atom feed
* pointers and associative maps
@ 2015-02-27 12:09 Jaromil
  2015-02-27 12:46 ` Jaromil
  0 siblings, 1 reply; 4+ messages in thread
From: Jaromil @ 2015-02-27 12:09 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1692 bytes --]


dear Zsh people,

I'm an old-time (ab)user of ZSh (started using it back 15yrs ago on
NetBSD), but this is the first time I interact with your lists since
actually I never needed to, your documentation is too good :^).
However, long due contact. Big up for ZSh release v5 BTW.

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 problem arises when I want to iterate through values, because using
a pointer modifier (P) and key/value modifiers (k)|(v) I get out only
the first char of the map field, not the whole string. I guess this is
related to the scoping of modifiers? here is how I do it:

# _map is the variable holding the name of the associative map

_num="${(P)#_map}"
for c in {1..$_num}; do
    sysread -o 1 <<EOF >> $_path
$_map+=("${${(Pk)_map}[$c]}" "${${(Pv)_map}[$c]}")
EOF


presuming that ${${(Pk)_map}[$c]} and ${${(Pv)_map}[$c]} should give in result
the full string, but instead they return the first char of the string, as if
the map index does not apply to the map but to the string object, so to say.

Am I missing something here? Does anyone has clues?

many thanks!

-- 

Jaromil, Dyne.org Free Software Foundry (est. 2000)
We are free to share code and we code to share freedom
GPG: 6113 D89C A825 C5CE DD02  C872 73B3 5DA5 4ACB 7D10

ZShaolin - Power console terminal for Android
https://play.google.com/store/apps/details?id=org.dyne.zshaolin
Free binaries for ZSh developers, just ask me privately!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 1513 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: pointers and associative maps
  2015-02-27 12:09 pointers and associative maps Jaromil
@ 2015-02-27 12:46 ` Jaromil
  2015-02-27 14:02   ` Jaromil
  0 siblings, 1 reply; 4+ messages in thread
From: Jaromil @ 2015-02-27 12:46 UTC (permalink / raw)
  To: zsh-users


whopsie

On Fri, 27 Feb 2015, Jaromil wrote:

> The problem arises when I want to iterate through values, because using
> a pointer modifier (P) and key/value modifiers (k)|(v) I get out only
> the first char of the map field, not the whole string. I guess this is
> related to the scoping of modifiers? here is how I do it:
> 
> # _map is the variable holding the name of the associative map
> 
> _num="${(P)#_map}"
> for c in {1..$_num}; do
>     sysread -o 1 <<EOF >> $_path
> $_map+=("${${(Pk)_map}[$c]}" "${${(Pv)_map}[$c]}")
> EOF
> 
> 
> presuming that ${${(Pk)_map}[$c]} and ${${(Pv)_map}[$c]} should give in result
> the full string, but instead they return the first char of the string, as if
> the map index does not apply to the map but to the string object, so to say.

solved! using ${(Pv)${_map}[$c]}

and sorry for the noise. I was confused by the fact that the code above
in a function was not giving the same result as: print ${${(Pv)_map}[$c]}
This might be something to look into, basically the automatic scoping
changes.

however the formula above is the right solution, I guess it has a more
explicit scoping of modifiers.

again thanks for ZSh, its an awesome portable tool.  I'll do my best to
contribute to it in some future, perhaps some extensions based on
libraries I've written.

ciao



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: pointers and associative maps
  2015-02-27 12:46 ` Jaromil
@ 2015-02-27 14:02   ` Jaromil
  2015-02-27 18:04     ` Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Jaromil @ 2015-02-27 14:02 UTC (permalink / raw)
  To: zsh-users


third reply to myself, now I'm embarassed. however:

> solved! using ${(Pv)${_map}[$c]}

this solves it only for values in the associative map, not for keys.

So my problem persists and I wonder if there are solutions to this:
use a pointer to an associative map to get out keys from it.

Here a small function to help reproduce the situation


typeset -A mappa
zkv-test() {
    mappa+=(key1 value1)
    mappa+=(key2 value2)
    mappa+=(key3 value3)
    
    _map=mappa
    _num="${(P)#_map}"

    for c in {1..$_num}; do
        print "$c/$_num: ${(Pk)${_map}[$c]} ${(Pv)${_map}[$c]}"
    done
}    



once launched, it prints:

1/3: 1 value1
2/3: 2 value2
3/3: 3 value3

where I believe it should be:

1/3: key1 value1
2/3: key2 value2
3/3: key3 value3


puzzling enough, after running the function one can do:

print ${${(Pk)_map}[$c]}

from the interactive console, moving the (Pk) modifier inside the inner
brackets, and then the key3 will be printed (or any, according to $c index)

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)

Am I missing something?

thanks for your patience about my cascade posting

ciao



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: pointers and associative maps
  2015-02-27 14:02   ` Jaromil
@ 2015-02-27 18:04     ` Bart Schaefer
  0 siblings, 0 replies; 4+ messages in thread
From: Bart Schaefer @ 2015-02-27 18:04 UTC (permalink / raw)
  To: zsh-users

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


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-02-27 18:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-27 12:09 pointers and associative maps Jaromil
2015-02-27 12:46 ` Jaromil
2015-02-27 14:02   ` Jaromil
2015-02-27 18:04     ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).