* Filtering array on index
@ 2018-10-25 11:29 Jesper Nygårds
2018-10-25 18:17 ` Mikael Magnusson
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Jesper Nygårds @ 2018-10-25 11:29 UTC (permalink / raw)
To: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 909 bytes --]
I have an array which is the result of using zparseopts on a specification
that makes it possible to specify several filters with a -v flag. The
resulting array might look like the following:
myarr=(-v filter1 -v filter2)
I want to get rid of the "-v" elements, but only when they are the flag,
and not the argument. In other words, I would the like the array (-v
filter1 -v -v) to result in (filter1 -v).
I had previously used:
${myarr:#-v}}
which worked well, as I could accept the fact that -v was not possible to
use as the option argument.
However, now I need to make sure that a -v argument is preserved, and I
thus need a compact way of specifying that I want to keep every other
element in the array.
The most compact way I have found is:
for dash arg in $myarr; do myarr[(r)$dash]=()
This works, but I was wondering if there's some more elegant solution,
preferrably without using iteration?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 11:29 Filtering array on index Jesper Nygårds
@ 2018-10-25 18:17 ` Mikael Magnusson
2018-10-25 18:55 ` Jesper Nygårds
2018-10-25 19:42 ` Daniel Shahaf
2018-10-25 20:21 ` Bart Schaefer
2019-07-23 3:38 ` Sebastian Gniazdowski
2 siblings, 2 replies; 15+ messages in thread
From: Mikael Magnusson @ 2018-10-25 18:17 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On 10/25/18, Jesper Nygårds <jesper.nygards@gmail.com> wrote:
> I have an array which is the result of using zparseopts on a specification
> that makes it possible to specify several filters with a -v flag. The
> resulting array might look like the following:
>
> myarr=(-v filter1 -v filter2)
>
> I want to get rid of the "-v" elements, but only when they are the flag,
> and not the argument. In other words, I would the like the array (-v
> filter1 -v -v) to result in (filter1 -v).
>
> I had previously used:
>
> ${myarr:#-v}}
>
> which worked well, as I could accept the fact that -v was not possible to
> use as the option argument.
>
> However, now I need to make sure that a -v argument is preserved, and I
> thus need a compact way of specifying that I want to keep every other
> element in the array.
>
> The most compact way I have found is:
> for dash arg in $myarr; do myarr[(r)$dash]=()
>
> This works, but I was wondering if there's some more elegant solution,
> preferrably without using iteration?
The above example doesn't work if you need to preserve the order (it
will just remove the first $dash it finds).
% a=(-v filter1 -v -v -v middle -v -v -v final)
% for dash arg in $a; do a[(r)$dash]=(); done; pl $a
filter1
middle
-v
-v
final
middle "should" be between the two remaining -v.
This works, but is still a loop obviously:
% for i in {$(($#a/2))..1}; do a[i*2-1]=(); done; pl $a
filter1
-v
middle
-v
final
(Note that it is necessary to iterate backwards as the indices will
change otherwise)
It is very easy to add -v back again however ;)
% a=( ${${:--v}:^^a} ); pl $a
-v
filter1
-v
-v
-v
middle
-v
-v
-v
final
--
Mikael Magnusson
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 18:17 ` Mikael Magnusson
@ 2018-10-25 18:55 ` Jesper Nygårds
2018-10-25 19:42 ` Daniel Shahaf
1 sibling, 0 replies; 15+ messages in thread
From: Jesper Nygårds @ 2018-10-25 18:55 UTC (permalink / raw)
To: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 426 bytes --]
Thank you. Nice examples. I hadn't thought about order, and in fact it's
not a problem in my use case.
I guess I'll have resign myself to using a loop. I was dreaming along the
lines of "a[e:<index is odd>:]=()", but no luck.
Although I understand the reason why zparseopts is designed this way, I've
always found it a bit cumbersome that there is no way to only get the
arguments to a possibly repeated flag into an array.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 18:17 ` Mikael Magnusson
2018-10-25 18:55 ` Jesper Nygårds
@ 2018-10-25 19:42 ` Daniel Shahaf
1 sibling, 0 replies; 15+ messages in thread
From: Daniel Shahaf @ 2018-10-25 19:42 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
Mikael Magnusson wrote on Thu, 25 Oct 2018 20:17 +0200:
> On 10/25/18, Jesper Nygårds <jesper.nygards@gmail.com> wrote:
> > I have an array which is the result of using zparseopts on a specification
> > that makes it possible to specify several filters with a -v flag. The
> > resulting array might look like the following:
> >
> > myarr=(-v filter1 -v filter2)
> >
> > I want to get rid of the "-v" elements, but only when they are the flag,
> > and not the argument. In other words, I would the like the array (-v
> > filter1 -v -v) to result in (filter1 -v).
> >
> > I had previously used:
> >
> > ${myarr:#-v}}
> >
> > which worked well, as I could accept the fact that -v was not possible to
> > use as the option argument.
> >
> > However, now I need to make sure that a -v argument is preserved, and I
> > thus need a compact way of specifying that I want to keep every other
> > element in the array.
> >
> > The most compact way I have found is:
> > for dash arg in $myarr; do myarr[(r)$dash]=()
> >
> > This works, but I was wondering if there's some more elegant solution,
> > preferrably without using iteration?
>
> The above example doesn't work if you need to preserve the order (it
> will just remove the first $dash it finds).
>
> % a=(-v filter1 -v -v -v middle -v -v -v final)
> % for dash arg in $a; do a[(r)$dash]=(); done; pl $a
> filter1
> middle
> -v
> -v
> final
>
> middle "should" be between the two remaining -v.
>
> This works, but is still a loop obviously:
> % for i in {$(($#a/2))..1}; do a[i*2-1]=(); done; pl $a
> filter1
> -v
> middle
> -v
> final
>
> (Note that it is necessary to iterate backwards as the indices will
> change otherwise)
Another option:
myarr=(-v filter1 -v filter2)
() { local i j; myarr=(); for i j; do myarr+=($j) ; done } "${myarr[@]}"
In zparseopts context we can probably assume the arguments to the -v
option don't contain literal NUL bytes, so perhaps something like this:
% myarr=( -v 'foo foo' -v 'bar bar' -v '' )
% printf -v x '\0k1%s\0k2%s\0v' "$myarr[@]"
% x=${x//$'\0k1-v\0k2'}
% x=${x%$'\0v'}
% () { typeset -p argv } "${(@ps.\0v.)x}"
typeset -g -a argv=( 'foo foo' 'bar bar' '' )
%
Is there a way to do this in O(N) time? (The array-based solutions are
quadratic complexity due to indexing/appending being O(N). I'm not sure
about the printf.)
Cheers,
Daniel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 11:29 Filtering array on index Jesper Nygårds
2018-10-25 18:17 ` Mikael Magnusson
@ 2018-10-25 20:21 ` Bart Schaefer
2018-10-25 20:42 ` dana
2019-07-23 3:38 ` Sebastian Gniazdowski
2 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2018-10-25 20:21 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On Thu, Oct 25, 2018 at 4:30 AM Jesper Nygårds <jesper.nygards@gmail.com> wrote:
>
> I have an array which is the result of using zparseopts on a specification
> that makes it possible to specify several filters with a -v flag. The
> resulting array might look like the following:
>
> myarr=(-v filter1 -v filter2)
What's your spec that produces this array? Here's my stab at an equivalent:
% set -- -v -v one -v "two -v" -v three -v
% vees=()
% zparseopts -a vees v+::
% print -lr -- $vees
-v
-vone
-vtwo -v
-vthree
-v
% print -lr -- ${vees#-v}
one
two -v
three
What am I missing?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 20:21 ` Bart Schaefer
@ 2018-10-25 20:42 ` dana
2018-10-26 4:14 ` Jesper Nygårds
0 siblings, 1 reply; 15+ messages in thread
From: dana @ 2018-10-25 20:42 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Jesper Nygårds, Zsh Users
On 25 Oct 2018, at 15:21, Bart Schaefer <schaefer@brasslantern.com> wrote:
>% zparseopts -a vees v+::
>...
>% print -lr -- ${vees#-v}
That method is the one i've seen used to solve this problem in completion
functions. But you have to make sure to add - at the end of the option spec if
you want it to work with mandatory (single-colon) arguments:
>An optional argument is put into the same array element as the option name
>(note that this makes empty strings as arguments indistinguishable). A
>mandatory argument is added as a separate element unless the ‘:-’ form is used,
>in which case the argument is put into the same element.
So if the argument to -v is mandatory you'd just use v+:- as the spec
dana
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 20:42 ` dana
@ 2018-10-26 4:14 ` Jesper Nygårds
2018-10-26 7:59 ` Jesper Nygårds
0 siblings, 1 reply; 15+ messages in thread
From: Jesper Nygårds @ 2018-10-26 4:14 UTC (permalink / raw)
To: Zsh Users; +Cc: Bart Schaefer, dana
[-- Attachment #1: Type: text/plain, Size: 199 bytes --]
Thank you!
The combination of Bart's and Dana's answers gives me the perfect solution
for my problem. I had skipped over the documentation for "-" as part of the
spec, thinking it was not relevant.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-26 4:14 ` Jesper Nygårds
@ 2018-10-26 7:59 ` Jesper Nygårds
2018-10-26 8:21 ` dana
0 siblings, 1 reply; 15+ messages in thread
From: Jesper Nygårds @ 2018-10-26 7:59 UTC (permalink / raw)
To: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 1438 bytes --]
OK, one is never satisfied, as always. I have a continuation of this option
parsing business. And for the record, I realize I could solve this with a
loop, but it's always fun to see how far the impressive zsh functionality
can take one.
In addition to my filter option, I also have an override option which as it
name suggests is meant to be used as an override for the filters. In other
words, I want to remove the overrides from the list of filters. I'm looking
for a compact expression for this.
The following doesn't quite do what I want, since I can find no way of
specifying that I want the "-f" prefix removed from the elements in
$overrides, before its elements are then removed from the $filter list:
% filters=(); overrides=()
% set -- -v one -v two -f one
% zparseopts -D -E v+:-=filters f+:-=overrides
% print -lr -- ${${filters#-v}:|overrides}
one
two
(I wanted only "one" to be printed)
The documentation for ":|" explicitly says "arrayname is the name (N.B.,
not contents) of an array variable", so I can't do the usual trick of
nesting the operations. Is there a way to achieve this?
On Fri, Oct 26, 2018 at 6:14 AM Jesper Nygårds <jesper.nygards@gmail.com>
wrote:
> Thank you!
>
> The combination of Bart's and Dana's answers gives me the perfect solution
> for my problem. I had skipped over the documentation for "-" as part of the
> spec, thinking it was not relevant.
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-26 7:59 ` Jesper Nygårds
@ 2018-10-26 8:21 ` dana
2018-10-26 9:28 ` Jesper Nygårds
2018-10-28 2:45 ` Bart Schaefer
0 siblings, 2 replies; 15+ messages in thread
From: dana @ 2018-10-26 8:21 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On 26 Oct 2018, at 02:59, Jesper Nygårds <jesper.nygards@gmail.com> wrote:
>The following doesn't quite do what I want, since I can find no way of
>specifying that I want the "-f" prefix removed from the elements in
>$overrides, before its elements are then removed from the $filter list:
>
>% filters=(); overrides=()
>% set -- -v one -v two -f one
>% zparseopts -D -E v+:-=filters f+:-=overrides
>% print -lr -- ${${filters#-v}:|overrides}
>one
>two
>
>(I wanted only "one" to be printed)
If the idea is to remove the overrides from the filters, shouldn't you have
wanted only 'two' printed?
If so, i guess this might qualify as 'compact':
${filters:#${~:-(${(j<|>)${(b)overrides/#-f/-v}})}}
Add (M) to the outer expansion if you want it the other way around
And if you still need the -v removed when you're done, just wrap the whole thing
in ${...#-v}
dana
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-26 8:21 ` dana
@ 2018-10-26 9:28 ` Jesper Nygårds
2018-10-28 2:45 ` Bart Schaefer
1 sibling, 0 replies; 15+ messages in thread
From: Jesper Nygårds @ 2018-10-26 9:28 UTC (permalink / raw)
To: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 376 bytes --]
On Fri, Oct 26, 2018 at 10:21 AM dana <dana@dana.is> wrote:
> If the idea is to remove the overrides from the filters, shouldn't you have
> wanted only 'two' printed?
>
Ah yes, I screwed up the comment, you interpreted what I wanted correctly.
Thank you for the solution. Now, I'll have to think about where exactly the
boundary between "compact" and "convoluted" goes. :-)
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-26 8:21 ` dana
2018-10-26 9:28 ` Jesper Nygårds
@ 2018-10-28 2:45 ` Bart Schaefer
1 sibling, 0 replies; 15+ messages in thread
From: Bart Schaefer @ 2018-10-28 2:45 UTC (permalink / raw)
To: dana; +Cc: Jesper Nygårds, Zsh Users
On Fri, Oct 26, 2018 at 1:22 AM dana <dana@dana.is> wrote:
>
> If so, i guess this might qualify as 'compact':
>
> ${filters:#${~:-(${(j<|>)${(b)overrides/#-f/-v}})}}
It's not even as difficult as that if you don't need to keep the "-v" prefixes:
% print -lr -- ${${filters#-v}:#${(j:|:b)~overrides#-f}}
two
If there are no filters that are a proper suffix of another filter,
you can do this to preserve the "-v" prefix:
% print -lr -- ${${filters}%${(j:|:b)~overrides#-f}}
> Add (M) to the outer expansion if you want it the other way around
Same above.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2018-10-25 11:29 Filtering array on index Jesper Nygårds
2018-10-25 18:17 ` Mikael Magnusson
2018-10-25 20:21 ` Bart Schaefer
@ 2019-07-23 3:38 ` Sebastian Gniazdowski
2019-07-23 7:42 ` Sebastian Gniazdowski
2 siblings, 1 reply; 15+ messages in thread
From: Sebastian Gniazdowski @ 2019-07-23 3:38 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On Thu, 25 Oct 2018 at 13:30, Jesper Nygårds <jesper.nygards@gmail.com> wrote:
>
> I have an array which is the result of using zparseopts on a specification
> that makes it possible to specify several filters with a -v flag. The
> resulting array might look like the following:
>
> myarr=(-v filter1 -v filter2)
I've recently had this problem. One other way to do it:
~ idx=0; olen=$#a+1; a=( ${a[@]/(#m)*/$a[$(( ++idx % 2 ? olen : idx ))]} )
~ print -rl -- $a
filter1
filter2
--
Sebastian Gniazdowski
News: https://twitter.com/ZdharmaI
IRC: https://kiwiirc.com/client/chat.freenode.net:+6697/#zplugin
Blog: http://zdharma.org
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2019-07-23 3:38 ` Sebastian Gniazdowski
@ 2019-07-23 7:42 ` Sebastian Gniazdowski
2019-07-23 8:03 ` Sebastian Gniazdowski
2019-09-08 8:59 ` Sebastian Gniazdowski
0 siblings, 2 replies; 15+ messages in thread
From: Sebastian Gniazdowski @ 2019-07-23 7:42 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On Tue, 23 Jul 2019 at 05:38, Sebastian Gniazdowski
<sgniazdowski@gmail.com> wrote:
>
> On Thu, 25 Oct 2018 at 13:30, Jesper Nygårds <jesper.nygards@gmail.com> wrote:
> > myarr=(-v filter1 -v filter2)
>
> I've recently had this problem. One other way to do it:
>
> ~ idx=0; olen=$#a+1; a=( ${a[@]/(#m)*/$a[$(( ++idx % 2 ? olen : idx ))]} )
Turns out the expression can be simpler because the math mode within
array's index is implicit, so:
idx=0; olen=$#a+1; a=( ${a[@]/(#m)*/$a[ ++idx % 2 ? olen : idx ]} )
I've also tried to construct an ::= assignment version. A safe.
different output variable version is:
b=(); idx=0; olen=$#a+1; : ${a[@]/(#m)*/${b[++idx]::=${a[idx % 2 ?
olen : idx]}}}
However, this yields 8 empty elements (for the a=(-v filter1 -v filter2 ))::
% print -rl -- "${(q)b[@]}"
''
''
...
prepending $idx after ::= yields following output:
''
1
''
3
''
5
''
7
I wonder what's going on? The code looks OK. Maybe it's a bug?
--
Sebastian Gniazdowski
News: https://twitter.com/ZdharmaI
IRC: https://kiwiirc.com/client/chat.freenode.net:+6697/#zplugin
Blog: http://zdharma.org
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2019-07-23 7:42 ` Sebastian Gniazdowski
@ 2019-07-23 8:03 ` Sebastian Gniazdowski
2019-09-08 8:59 ` Sebastian Gniazdowski
1 sibling, 0 replies; 15+ messages in thread
From: Sebastian Gniazdowski @ 2019-07-23 8:03 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
On Tue, 23 Jul 2019 at 09:42, Sebastian Gniazdowski
<sgniazdowski@gmail.com> wrote:
> I wonder what's going on? The code looks OK. Maybe it's a bug?
So it seems that the ++idx within the ::=-treated array brackets is
executed twice. This might get considered a bug, but there's a chance
that this is how the code is arranged. After moving ++idx outside, the
code works:
% a=(-v filter1 -v filter2 )
% idx=0; olen=$#a+1; : ${a[@]/(#m)*/$((++idx))${a[idx]::=${a[idx % 2 ?
olen : idx]}}}
% print $a
filter1
filter2
Of course the empty elements are still there so an empty-element
eradicating use like above is needed.
--
Sebastian Gniazdowski
News: https://twitter.com/ZdharmaI
IRC: https://kiwiirc.com/client/chat.freenode.net:+6697/#zplugin
Blog: http://zdharma.org
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Filtering array on index
2019-07-23 7:42 ` Sebastian Gniazdowski
2019-07-23 8:03 ` Sebastian Gniazdowski
@ 2019-09-08 8:59 ` Sebastian Gniazdowski
1 sibling, 0 replies; 15+ messages in thread
From: Sebastian Gniazdowski @ 2019-09-08 8:59 UTC (permalink / raw)
To: Jesper Nygårds; +Cc: Zsh Users
[-- Attachment #1: Type: text/plain, Size: 434 bytes --]
23 July 2019, 09:42 Sebastian Gniazdowski <sgniazdowski@gmail.com> wrote:
> Turns out the expression can be simpler because the math mode within
> array's index is implicit, so:
>
> idx=0; olen=$#a+1; a=( ${a[@]/(#m)*/$a[ ++idx % 2 ? olen : idx ]} )
>
The expression can be even simpler if (valid in Zsh, just resolving to
empty element when no ksharrays) index 0 will be used:
idx=0; a=( ${a[@]/(#m)*/$a[ ++idx%2 ? 0 : idx ]} )
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2019-09-08 9:00 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-25 11:29 Filtering array on index Jesper Nygårds
2018-10-25 18:17 ` Mikael Magnusson
2018-10-25 18:55 ` Jesper Nygårds
2018-10-25 19:42 ` Daniel Shahaf
2018-10-25 20:21 ` Bart Schaefer
2018-10-25 20:42 ` dana
2018-10-26 4:14 ` Jesper Nygårds
2018-10-26 7:59 ` Jesper Nygårds
2018-10-26 8:21 ` dana
2018-10-26 9:28 ` Jesper Nygårds
2018-10-28 2:45 ` Bart Schaefer
2019-07-23 3:38 ` Sebastian Gniazdowski
2019-07-23 7:42 ` Sebastian Gniazdowski
2019-07-23 8:03 ` Sebastian Gniazdowski
2019-09-08 8:59 ` Sebastian Gniazdowski
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).