Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re^3: Fast - Compact That String

by BrowserUk (Pope)
on Feb 10, 2012 at 20:06 UTC ( #953120=note: print w/replies, xml ) Need Help??


in reply to Re^2: Fast - Compact That String
in thread Fast - Compact That String

An explanation of the code as requested:

## Map the numbers, 0 .. 36 to the symbols we use ## to represent the number in base37 my @c1 = (' ', '0'..'9', 'A'..'Z' ); sub fromB37 { my $n = shift; ## Get the number to convert ## Allocate space for the Base37 representation ## Initialise it to the representation of 0 (six spaces) my $s = ' '; ## For each position in the string for( 0 .. 5 ) { ## extract the next base37 digit value ## look up its representaion character ## and assign it to the 'right place' i the string. substr( $s, $_, 1 ) = $c1[ $n%37 ] ); ## dividing by 37 effectively right-shifts ## the last digit's value out of the number $n /= 37; } $s; } my @c2; ## Map the ordinal values of the symbols ## to their numeric values (0 .. 37) ## The sparse array is faster than a hash $c2[ ord( $c1[ $_ ] ) ] = $_ for 0 .. 36; sub toB37 { my $n = 0; ## initialise our return value to 0 ## split the base37 representation ## into a list of the ordinal values of the symbols ## and reverse their order to match that produced by fromB37() for( reverse unpack 'C*', $_[0] ) { ## multiple the running total by 37 ## (effectively left-shifting the accumulator ## to accommodate the next digit.) ## and add value of the next base37 digit ## by looking it up in the mapping array $n = $n * 37 + $c2[ $_ ]; } ## return the accumulated value. $n; }

As mbethke points out, these treat the base37 number in 'little-endian' fashion. This because you emphasised compression and speed, with no mention of needing to manipulate the compressed values numerically (sorting).

To get the sortable, big-endian representation, you could use:

my @c1 = (' ', '0'..'9', 'A'..'Z' ); sub fromB37 { my $n = shift; my $s = ' '; substr( $s, $_, 1, $c1[ $n%37 ] ), $n /= 37 for 5, 4, 3, 2, 1, 0; $s; } my @c2; $c2[ ord( $c1[ $_ ] ) ] = $_ for 0 .. 36; sub toB37 { my $n = 0; $n = $n * 37 + $c2[$_] for unpack 'C*', $_[0]; $n; }

Which actually works out a bit quicker still, but not as fast as mbethke's unrolled version.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

The start of some sanity?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://953120]
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2018-06-20 07:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (116 votes). Check out past polls.

    Notices?