zsh-users
 help / color / mirror / code / Atom feed
* How to iterate over an array of associative arrays
@ 2013-07-14 12:35 Thorsten Kampe
  2013-07-14 13:10 ` Mikael Magnusson
  0 siblings, 1 reply; 10+ messages in thread
From: Thorsten Kampe @ 2013-07-14 12:35 UTC (permalink / raw)
  To: zsh-users

Hi,

I'd like to iterate over elements of an array. The elements are 
associative arrays. This is my code:

"""
#! /usr/bin/env zsh
emulate -R zsh

setopt nounset

declare -A elem AssocArr1 AssocArr2

AssocArr1=(key value1)
AssocArr2=(key value2)

array=($AssocArr1 $AssocArr2)

for elem in $array
    do echo $elem[key]
done
"""

./test.zsh:14: elem[key]: parameter not set

Thorsten


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 12:35 How to iterate over an array of associative arrays Thorsten Kampe
@ 2013-07-14 13:10 ` Mikael Magnusson
  2013-07-14 13:36   ` Thorsten Kampe
  0 siblings, 1 reply; 10+ messages in thread
From: Mikael Magnusson @ 2013-07-14 13:10 UTC (permalink / raw)
  To: Thorsten Kampe; +Cc: Zsh Users

On 14 July 2013 14:35, Thorsten Kampe <thorsten@thorstenkampe.de> wrote:
> Hi,
>
> I'd like to iterate over elements of an array. The elements are
> associative arrays. This is my code:
>
> """
> #! /usr/bin/env zsh
> emulate -R zsh
>
> setopt nounset
>
> declare -A elem AssocArr1 AssocArr2
>
> AssocArr1=(key value1)
> AssocArr2=(key value2)
>
> array=($AssocArr1 $AssocArr2)

Do you really want these $ here?

> for elem in $array
>     do echo $elem[key]
> done
> """
>
> ./test.zsh:14: elem[key]: parameter not set

You need to use the (P) flag to access a parameter indirectly.
% foo=(one two)
% bar=foo
% echo $bar[2]
o
% echo ${${bar}[2]}
o
% echo ${${(P)bar}[2]}
two

--
Mikael Magnusson


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 13:10 ` Mikael Magnusson
@ 2013-07-14 13:36   ` Thorsten Kampe
  2013-07-14 16:14     ` Valodim Skywalker
                       ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Thorsten Kampe @ 2013-07-14 13:36 UTC (permalink / raw)
  To: zsh-users

* Mikael Magnusson (Sun, 14 Jul 2013 15:10:22 +0200)
> On 14 July 2013 14:35, Thorsten Kampe <thorsten@thorstenkampe.de> 
wrote:
> > Hi,
> >
> > I'd like to iterate over elements of an array. The elements are
> > associative arrays. This is my code:
> >
> > """
> > #! /usr/bin/env zsh
> > emulate -R zsh
> >
> > setopt nounset
> >
> > declare -A elem AssocArr1 AssocArr2
> >
> > AssocArr1=(key value1)
> > AssocArr2=(key value2)
> >
> > array=($AssocArr1 $AssocArr2)
> 
> Do you really want these $ here?

Yes, I really wanted to pass the actual associative arrays, but if I can 
pass the names that's fine with me, too.

> You need to use the (P) flag to access a parameter indirectly.
> % foo=(one two)
> % bar=foo
> % echo $bar[2]
> o
> % echo ${${bar}[2]}
> o
> % echo ${${(P)bar}[2]}
> two

Doesn't work for me:

"""
array=(AssocArr1 AssocArr2)

for elem in $array
    do echo ${${(P)elem}[key]}
done
"""

[empty output]

Thorsten


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 13:36   ` Thorsten Kampe
@ 2013-07-14 16:14     ` Valodim Skywalker
  2013-07-14 16:49       ` Thorsten Kampe
  2013-07-14 17:21     ` Peter Stephenson
  2013-07-14 18:05     ` Bart Schaefer
  2 siblings, 1 reply; 10+ messages in thread
From: Valodim Skywalker @ 2013-07-14 16:14 UTC (permalink / raw)
  To: zsh-users

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

I couldn't get that to work, either. The associative part seems to be
lost after (P) indirection, since elements can be addressed numerically.

Anyways, here's an alternative suggestion:

  typeset -A a1 a2;
  arr=( a2 a1 ); a1=(key val1); a2=(key val2);
  for i in $arr; echo ${(e):-\$$i\[key]}

This uses (e), so beware of security implications.

 - V

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

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

* Re: How to iterate over an array of associative arrays
  2013-07-14 16:14     ` Valodim Skywalker
@ 2013-07-14 16:49       ` Thorsten Kampe
  2013-07-14 17:25         ` Valodim Skywalker
  0 siblings, 1 reply; 10+ messages in thread
From: Thorsten Kampe @ 2013-07-14 16:49 UTC (permalink / raw)
  To: zsh-users

* Valodim Skywalker (Sun, 14 Jul 2013 18:14:37 +0200)
> 
> I couldn't get that to work, either. The associative part seems to be
> lost after (P) indirection, since elements can be addressed numerically.
> 
> Anyways, here's an alternative suggestion:
> 
>   typeset -A a1 a2;
>   arr=( a2 a1 ); a1=(key val1); a2=(key val2);
>   for i in $arr; echo ${(e):-\$$i\[key]}
> 
> This uses (e), so beware of security implications.

...works. What for christ's sake does it do? (Of course, I could try to 
figure it out on my own, but that might take a few days...)

Thorsten


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 13:36   ` Thorsten Kampe
  2013-07-14 16:14     ` Valodim Skywalker
@ 2013-07-14 17:21     ` Peter Stephenson
  2013-07-14 19:57       ` Thorsten Kampe
  2013-07-14 18:05     ` Bart Schaefer
  2 siblings, 1 reply; 10+ messages in thread
From: Peter Stephenson @ 2013-07-14 17:21 UTC (permalink / raw)
  To: zsh-users

On Sun, 14 Jul 2013 15:36:03 +0200
Thorsten Kampe <thorsten@thorstenkampe.de> wrote:
> Yes, I really wanted to pass the actual associative arrays, but if I can 
> pass the names that's fine with me, too.

So maybe you're looking for:


typeset -A AssocArr1 AssocArr2
typeset -a array
typeset key value

AssocArr1=(key1 value1)
AssocArr2=(key2 value2)

# array is a normal array containing key/value pairs
array=(${(kv)AssocArr1} ${(kv)AssocArr2})

# scan array by pairs
for key value in $array
    do echo $key $value
done


?

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 16:49       ` Thorsten Kampe
@ 2013-07-14 17:25         ` Valodim Skywalker
  0 siblings, 0 replies; 10+ messages in thread
From: Valodim Skywalker @ 2013-07-14 17:25 UTC (permalink / raw)
  To: zsh-users

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

The (e) flag is basically eval for parameter expansion. Using :-, an
inline string is created which looks like $a1[key], where the $ is the
escaped one, the a1 comes from $i, and \[key] is just added, escaping
the [ so it's not used as array subscript of $i.

Cheers,

 - V


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

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

* Re: How to iterate over an array of associative arrays
  2013-07-14 13:36   ` Thorsten Kampe
  2013-07-14 16:14     ` Valodim Skywalker
  2013-07-14 17:21     ` Peter Stephenson
@ 2013-07-14 18:05     ` Bart Schaefer
  2 siblings, 0 replies; 10+ messages in thread
From: Bart Schaefer @ 2013-07-14 18:05 UTC (permalink / raw)
  To: Thorsten Kampe, zsh-users

On Jul 14,  3:36pm, Thorsten Kampe wrote:
}
} > > AssocArr1=(key value1)
} > > AssocArr2=(key value2)
} > >
} > > array=($AssocArr1 $AssocArr2)
} > 
} > Do you really want these $ here?
} 
} Yes, I really wanted to pass the actual associative arrays, but if I can 
} pass the names that's fine with me, too.

The shell language is text-oriented and can be though of as strictly
pass-by-value, so there's no way to create a nested data structure; the
values of the array cannot be direct references to other arrays.

} > You need to use the (P) flag to access a parameter indirectly.

Ksh namerefs, which are partly emulated by zsh's (P) flag, allow you to
simulate references but are not true object handles.

} Doesn't work for me:
} 
} """
} array=(AssocArr1 AssocArr2)
} 
} for elem in $array
}     do echo ${${(P)elem}[key]}
} done
} """

Unfortunately even though ${(P)elem} can access by reference, it can only
"return" (expand that reference) by value, and the shell has only two kinds
of values: strings or plain arrays.

Fortunately, although associative array keys/values are not maintained in
any predictable order, they are guaranteed to be returned in a consistent
order (as long as no new elements are inserted between accesses) so this
can be done:

"""
declare -A AssocArr
AssocArr=(key1 value1 key2 value2 key3 value3)
ref=AssocArr

print position of key2 is ${${(kP)ref}[(i)key2]}
print value for key2 is ${${(P)ref}[${${(@kP)ref}[(i)key2]}]}
"""

The extra (@) in there is because $arr[key] puts key in double-quoted
context, so you have to force ${(P)ref} to remain an array for the
subscript operation.


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 17:21     ` Peter Stephenson
@ 2013-07-14 19:57       ` Thorsten Kampe
  2013-07-14 22:57         ` Bart Schaefer
  0 siblings, 1 reply; 10+ messages in thread
From: Thorsten Kampe @ 2013-07-14 19:57 UTC (permalink / raw)
  To: zsh-users

* Peter Stephenson (Sun, 14 Jul 2013 18:21:17 +0100)
> On Sun, 14 Jul 2013 15:36:03 +0200
> Thorsten Kampe <thorsten@thorstenkampe.de> wrote:
> > Yes, I really wanted to pass the actual associative arrays, but if I can 
> > pass the names that's fine with me, too.
> 
> So maybe you're looking for:
> 
> typeset -A AssocArr1 AssocArr2
> typeset -a array
> typeset key value
> 
> AssocArr1=(key1 value1)
> AssocArr2=(key2 value2)
> 
> # array is a normal array containing key/value pairs
> array=(${(kv)AssocArr1} ${(kv)AssocArr2})
> 
> # scan array by pairs
> for key value in $array
>     do echo $key $value
> done

Looks good but as far as I can see it does not allow me to iterate over 
assiociative arrays so I can get the value of a certain key from all 
arrays.

Say I have...

AssocArr1=(key1 value11
           key2 value12)

AssocArr2=(key1 value21
           key2 value22)

So how do I iterate over...

    array=(AssocArr1 AssocArr2)

...so that I get value12 (= AssocArr1[key2]) in the first iteration and 
value22 (= AssocArr2[key2]) in the second?

Thorsten


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

* Re: How to iterate over an array of associative arrays
  2013-07-14 19:57       ` Thorsten Kampe
@ 2013-07-14 22:57         ` Bart Schaefer
  0 siblings, 0 replies; 10+ messages in thread
From: Bart Schaefer @ 2013-07-14 22:57 UTC (permalink / raw)
  To: Thorsten Kampe, zsh-users

On Jul 14,  9:57pm, Thorsten Kampe wrote:
}
} Say I have...
} 
} AssocArr1=(key1 value11
}            key2 value12)
} 
} AssocArr2=(key1 value21
}            key2 value22)
} 
} So how do I iterate over...
} 
}     array=(AssocArr1 AssocArr2)

Using the example in my earlier email ...

for ref in $array
do
   print ${${(P)ref}[${${(@kP)ref}[(i)key2]}]}
done


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

end of thread, other threads:[~2013-07-14 22:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-14 12:35 How to iterate over an array of associative arrays Thorsten Kampe
2013-07-14 13:10 ` Mikael Magnusson
2013-07-14 13:36   ` Thorsten Kampe
2013-07-14 16:14     ` Valodim Skywalker
2013-07-14 16:49       ` Thorsten Kampe
2013-07-14 17:25         ` Valodim Skywalker
2013-07-14 17:21     ` Peter Stephenson
2013-07-14 19:57       ` Thorsten Kampe
2013-07-14 22:57         ` Bart Schaefer
2013-07-14 18:05     ` 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).