Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^3: reduce like iterators

by ELISHEVA (Prior)
on Jan 03, 2011 at 20:04 UTC ( [id://880254]=note: print w/replies, xml ) Need Help??


in reply to Re^2: reduce like iterators
in thread reduce like iterators

Perl also lets you use parameters to roll your own block syntax. Here is a slightly different definition that would allow you to do arbitrary operations on the first element of each run in a list:

sub compress(&@) { my $cr=shift; my$x; my @aResult; local $_=undef; foreach (map { defined($x) ? defined($_) && ($x eq $_) ? () : ($x = $_) : defined($_) ? ($x = $_) : () } @_) { push @aResult, $cr->(); } return @aResult; } my @aData=(qw(a a a a b c c a a d e e e e), undef, undef, qw(f g g)); my @aCompressed = compress {'*' . (defined($_)?$_:'<undef>').'*'} @aData; print "compress: @aCompressed\n"; # output: compress: *a* *b* *c* *a* *d* *e* *<undef>* *f* *g*

Or if you want to be able to work with the current run value ($b) and the previous run value $a, you could do something like this:

sub compressPair(&@) { my $cr=shift; my @aResult; my $x; local $a=undef; local $b=undef; foreach (map { defined($x) ? ($x eq$_?():($x=$_)) : defined($_)?($x=$_):() } @_) { $a=$b; $b=$_; push @aResult, $cr->(); } return @aResult; } my @aData=(qw(a a a a b c c a a d e e e e), undef, undef, qw(f g g)); my @aCompressed = compressPairs { '(' . (defined($a)?$a:'<undef>') . ',' . (defined($b)?$b:'<undef>') . ')' } @aData; print "compressPairs: @aCompressed\n"; #output compressPairs: (<undef>,a) (a,b) (b,c) (c,a) (a,d) (d,e) (e,<undef>) ( +<undef>,f) (f,g)

There is almost no limit to what you could create. For example, if you wanted to be able to group items, you could additionally track the number of items in each run and set $_ to number of items in the current run:

sub compressPairsWithCount(&@) { my $cr=shift; my @aResult; my $x; my @aRuns=(0); my $i=defined($_[0])?-1:0; my $j=0; local $a=undef; local $b=undef; foreach (map { if ((defined($x) && defined($_) && ($x eq $_)) || (!defined($x) && !defined($_))) { $aRuns[$i]++; () } else { $aRuns[++$i]=1; ($x = $_); } } @_) { $a=$b; $b=$_; $_=$aRuns[$j++]; push @aResult, $cr->(); } return @aResult; } @aCompressed = compressPairsWithCount { '(' . (defined($a)?$a:'<undef>') . ',' . (defined($b)?$b:'<undef>') . "=$_)" } @aData; print "compressPairsWithCount: @aCompressed\n"; #outputs compressPairsWithCount: (<undef>,a=4) (a,b=1) (b,c=2) (c,a=2) (a,d=1) +(d,e=4) (e,<undef>=2) (<undef>,f=1) (f,g=2)

Would that do what you want?

Update: added yet another block iterator, this time one that could be used for generating groups as in the Haskell function above.

Update: put in readmore tags

Update: fixed 3rd example so it prints count of current (not previous) run.

Replies are listed 'Best First'.
Re^4: reduce like iterators
by LanX (Saint) on Jan 03, 2011 at 22:24 UTC
    this is a reply I wrote about an hour ago but forgot to post, thankfully I was able to find the preview in the history of one of my tabs, sorry if it's not up to date to your updates

    > Would that do what you want?

    Thanks Elisheva, but I don't have an implementation problem.

    I'm well aware that there are plenty of possibilities to realize a specialized function, e.g. with a prototyped code-block like you demonstrated.

    I'm rather interested in a good design, to produce elegant, expressive and easily maintainable code.

    As I said, I wouldn't like to reimplement each function in List::Util and List::MoreUtils as "reduce like" versions, with the additional problem to find and memorize new names for those functions.

    Thats why I'm meditating about additional special vars to augment those functions with the needed tweaks in a orthogonal way, without breaking the original functionality.

    As an analogue, see how many RegEx-functions other languages like PHP have to implement special functionalities, which are realized in Perl with special vars or modifiers.

    Cheers Rolf

      How is memorizing a new special var any different than memorizing a new BLOCK LIST function name? Either way, you are having to memorize something new. Also depending on how you define your block list function, you are effectively making $a, $b, or $_ into a special purpose variable of your own choosing.

      Also I'm not sure I understand how you separate the notion of special variable from block function/syntax. Special variables generally are part of a process and the process drives the variables. Regexs are complicated processes with lots of mid-process data so they have lots of special variables. Sort is fairly simple, so it has just two $a and $b. But in each case, accompanying the special variable is a function or special syntax. $1 is associated with the syntax of a regular expression. $_ is associated with sort, grep, map, and for not because the variable has special meaning in and of itself, but because each of these function need only a current list member and $_ is symbol used when we need the current item of the list.

      If we were to start adding special variables to grep/sort/map and other list processing functions, I fear we'd bloat the amount of information that Perl would have to track on each iteration. I suppose the bloat could be avoided if Perl could decide what information to track by surveying the contents of the block and any special variables used within. So for example, if $N was reserved for run count, it would only track run count if the grep/map/foreach block contained $N. Is that the kind of thing you are getting at?

      There are so many possibilities of things one might want to track where would it stop? Run length? Cumulative frequency of the current value? Minimum found so far? Maximum found so far? Moving average? Wouldn't making all of these part of the language, each with its own special symbol make the language more complex? Wouldn't it be wiser to stick with the minimum number of symbols needed to do the job and let those who need more add them via the block/list syntax? An iteration through a list has to have a current member or else it makes no sense as an iterator. The special variable $_ is essential. A sort process needs two items to compare otherwise there is nothing to sort. $a and $b are essential to the process. But other "state of the list" variables are not. They are application dependent and perhaps should be left to applications to define on an as needed basis.

      I guess I still don't get what you are striving for, design wise. A reflection on the value of different kinds of syntax elements? How best to use the tools at hand in Perl? The ideal minimal set of iterators, whether they be represented by new block function names or new special variables or some combination of the two?

        > How is memorizing a new special var any different than memorizing a new BLOCK LIST function name?

        reduce iterates over neighboring couples, i.e. one iteration less.

        So each new iterator needs a new name ...

        Lets suppose appending _couple instead of inventing individual names is sufficient.

        first_couple {$a != $b} 0 ..9 any_couple ... map_couple ... ...

        when letting $_ iterating normally with $^PRE activated you might want to add _ante everywhere

        map_ante { $_ == $^PRE ? $_ : () } grep_ante ...

        simply having special vars which only change behavior when they are used within the block, simplifies notation.

        Even if one doesn't touch classical iterator names to guaranty backwards compatibility, already those three cases can be integrated into one naming convention:

        xgrep { $_ == 9 } LIST # like ordinary grep xgrep { $a == $b } LIST # like grep_couple xgrep { $^PRE == $_ } LIST # like grep_ante xgrep { $a == $^PRE } LIST # ERROR xfirst ... # and so on

        In other words orthogonality helps to keep the namespace slim. And I'm sure there are still other variants of special vars to be considered.

        I promise to answer your other points soon, unfortunately I don't have the possibility at the moment...

        Cheers Rolf

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://880254]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-23 06:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found