Index finite lists of positive integers: Difference between revisions

m (→‎Bijection: allowing empty list is probably more correct)
(→‎{{header|Perl 6}}: style upgrade)
Line 226:
Here is a bijective solution that does not use string operations.
 
<lang perl6>submulti infix:<rad> expand(Int) $n is copy, Int $dimension where * >{ 0) {}
multi infix:<rad> ($a) { $a }
return $n if $dimension == 1;
multi infix:<rad> ($a, $b) { $a * $*RADIX + $b }
 
multi expand(Int $n is copy, 1) { $n }
multi expand(Int $n is copy, Int $*RADIX) {
my \RAD = $*RADIX;
 
my @reversed-digits = gather while $n > 0 {
take $n % $dimensionRAD;
$n div= $dimensionRAD;
}
 
return map {
eager for ^RAD {
reduce * * $dimension + *, 0, 0,
[rad] reverse @reversed-digits[$_, * + $dimensionRAD ... *]
}, ^$dimension;
sub compress(*@n is copy where @n > 0) {
my $dimension = @n.elems;
return @n[0] if $dimension == 1;
reduce * * $dimension + *, 0, 0,
reverse gather while @n.any > 0 {
(state $i = 0) %= $dimension;
take @n[$i] % $dimension;
@n[$i] div= $dimension;
$i++;
}
}
submulti rankcompress(@n) {where compress compress(@n == 1), +{ @n[0] - 1}
submulti compress(*@n is copy where @n > 0) {
sub unrank(Int $n) { my ($a, $b) = expand($n, 2); expand $a, $b + 1 }
my \RAD = my $dimension*RADIX = @n.elems;
 
[rad] reverse gather while @n.any > 0 {
(state $i = 0) %= $dimensionRAD;
take @n[$i] % $dimensionRAD;
@n[$i] div= $dimensionRAD;
$i++;
}
sub rank(@n) { compress (compress(@n), @n - 1)}
sub unrank(Int $n) { my ($a, $b) = expand( $n, 2); expand $a, $b + 1 }
say my @list = (^10).roll((2..20).pick);
say my $rank = rank @list;
say unrank $rank;
 
for ^10 {
my @unrank = unrank $_;
say $_, " <-> [", @unrank, "] <-> ", rank @unrank;</lang>
}</lang>
 
{{out}}
<pre>7 1 2 2 67 52 0 1 0 9 3 7 9 1 6 0 4 2
22307919125181853053469970435648803626620419
77692871663419443
7 1 2 2 67 52 0 1 0 9 3 7 9 1 6 0 4 2
0 <-> [0] <-> 0
1 <-> [1] <-> 1
Anonymous user