in reply to Re^2: Getting Pairs of 2nd-ary Keys in HoHoA
in thread Getting Pairs of 2nd-ary Keys in HoHoA
But can you explain what is `memoization`?
"Memoization" is a standard speed-optimization technique: one caches often-used results so they don't need to be recomputed.
And if you don`t mind little explanation, why you do each step that way?
OK, I've simplified the code; now it's easier to explain. Here it is:
Basically the problem entails to solving two subproblems:my @ss = map sort_inner( [ keys %{ $_->[ 0 ] } ] ), sort { $a->[ 1 ] <=> $b->[ 1 ] } map [ $HoHoA{ $_ }, substr( $_, 3 ) ], keys %HoHoA; for my $i ( 0..$#ss-1 ) { my $si = $ss[ $i ]; for my $j ( $i+1..$#ss ) { my $sj = $ss[ $j ]; for my $ki ( @$si ) { for my $kj ( @$sj ) { print "$ki - $kj\n"; } } } } sub sort_inner { return [ map $_->[ 0 ], sort { $a->[ 1 ] <=> $b->[ 1 ] || $a->[ 2 ] <=> $b->[ 2 ] } map [ $_, /\d+/g ], @{ $_[ 0 ] } ] }
Here @$si and @$sj represent two (suitably sorted) lists of inner keys, and the loops ensure that we get all possible ordered pairs with the first element from @$si and the second one from @$sj.for my $ki ( @$si ) { for my $kj ( @$sj ) { print "$ki - $kj\n"; } }
The other loop handles the first subproblem:
This runs over all pairs of (sorted) lists ( $ss[ $i ], $ss[ $j ] ) such that 0 ≤ $i < $j < @ss.for my $i ( 0..$#ss-1 ) { my $si = $ss[ $i ]; for my $j ( $i+1..$#ss ) { my $sj = $ss[ $j ]; # ... } }
The remaining problem is to sort the sets of keys so that the looping above produces the output in the desired order. Two different levels of sorting are required: for each inner hash of %HoHoA the keys need to be sorted to produce a set of sorted keys; and these sets of sorted keys must be stored in the right order in the array @ss. The code does this with a pair of nested Schwartzian transforms. The inner one encapsulated in the function sort_inner, which sorts the elements of the input array according to the two numbers contained in each key. These two numbers are extracted via the regular expression /\d+/g evaluated in a list context. The actual sort function is
which sorts array refs numerically according to their second elements, or, in case of ties, their third elements (the first element is the typical ST payload).{ $a->[ 1 ] <=> $b->[ 1 ] || $a->[ 2 ] <=> $b->[ 2 ] }
The outer ST is
The keys are sorted numerically on the substring obtained by removing the first 3 characters (i.e. the word "set"). (I could have just as well used the same /\d+/g construct as before.) The only non-standard aspect of this ST is that the last step, instead of simply extracting the payload with $_->[ 0 ] as before, it does one further transformation on it (more about this in a minute). It is equivalent to the more usual looking STmy @ss = map sort_inner( [ keys %{ $HoHoA{ $_->[ 0 ] } } ] ), sort { $a->[ 1 ] <=> $b->[ 1 ] } map [ $_, substr( $_, 3 ) ], keys %HoHoA;
followed by one more map map:my @tmp = map $_->[ 0 ], sort { $a->[ 1 ] <=> $b->[ 1 ] } map [ $_, substr( $_, 3 ) ], keys %HoHoA;
I'v just collapsed these two steps to eliminate the intermediate @tmp array.my @ss = map sort_inner( [ keys %{ $HoHoA{ $_ } } ] ), @tmp;
The transformation given by the expression
returns an array ref the keys of the inner hash corresponding to $HoHoA{ $k }, but sorted by sort_inner.sort_inner( [ keys %{ $HoHoA{ $k } } ] )
In the end, @ss is just an AoA. Or rather, it is a SAoSA: a sorted array of sorted arrays.
the lowliest monk
|
|---|