Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Determing "numeric value" of string?

by Anonymous Monk
on Feb 11, 2009 at 19:35 UTC ( #743135=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have an interesting problem...I've built a sort routine tied to each column in the ListCtrl WxPerl widget but unfortunately the sort method will only sort numbers. Heres my solution if it will work:

Assign a numeric value to each string so when sorted I can use that enumerated value to do my comparison. Does anyone know if this will work? If so is there an easy way to assign my list of strings a numeric value so when sorted numericaly the strings are sorted alphabetically?

Thanks

Comment on Determing "numeric value" of string?
Re: Determing "numeric value" of string?
by Fletch (Chancellor) on Feb 11, 2009 at 19:39 UTC

    Slightly evil deep mojo, but dualvar from Scalar::Util lets you make a scalar that behaves like $! (string when used as a string, numeric when used as a number). Alternately overload numerification.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Determing "numeric value" of string?
by kennethk (Monsignor) on Feb 11, 2009 at 19:40 UTC

    You've just rediscovered the Schwartzian Transform.

    Update: Misunderstood where the OP was troubled - disregard.

      oh boy...I was hoping it might be a little easier as most things are with Perl :)

      Here is some test code :

      use warnings; use strict; comparison( "This is another String", "This is yet another string"); comparison( "T5", "T4"); comparison( "1 begins this string", "2"); sub comparison { my($a,$b) = @_; print "ORD: " . ord($a) . "\n"; print "ORD: " . ord($b) . "\n"; if ( $a le $b ) { print " string :$a: is less than string :$b:\n\n"; } else { print " string :$a: is greater than string :$b:\n\n"; } }
      Still, my problem is I can't get the numerical value of the strings I'm comparing...
Re: Determing "numeric value" of string?
by DStaal (Chaplain) on Feb 11, 2009 at 19:45 UTC

    In general, this is a very hard problem to get into in the first place using Perl...

    How about you show us some code. I'll bet we can figure out how to make it work without trying to assign numeric values to strings.

      Feel free...but I've spent hours on this. Here is my test script, note the section that works and does not work.
      use Wx; package MyFrame; use strict; use vars qw(@ISA); @ISA = qw(Wx::Frame); use Wx qw(:everything); my %hash = (); my $sort = 'asc'; my $acol = 0; sub new { my( $class ) = shift; my( $this ) = $class->SUPER::new( undef, -1, $_[0], [ @_[1, 2] ], [ @_[3, 4] ] ); $this->{LISTCTRL} = Wx::ListCtrl->new( $this, -1, wxDefaultPositio +n, wxDefaultSize, wxLC_REPORT ); $this->{LISTCTRL}->InsertColumn( 0, "Column 1" ); $this->{LISTCTRL}->InsertColumn( 1, "Column 2" ); $this->{LISTCTRL}->InsertColumn( 2, "Column 3" ); # control hidden to speed up insertion $this->{LISTCTRL}->Show( 0 ); my( $id ); my( $elements ) = 5; foreach ( 1 .. $elements - 1 ) { # WORKS #my $data = int(rand(100)); #my $data2 = int(rand(100)); #my $data3 = int(rand(100)); # DOES NOT WORK my $data = "STRING: " . int(rand(100)); my $data2 = "STRING: " . int(rand(100)); my $data3 = "STRING: " . int(rand(100)); $id = $this->{LISTCTRL}->InsertStringItem( $_, $data ); $this->{LISTCTRL}->SetItemData( $id, $data ); $this->{LISTCTRL}->SetItem( $id, 1, $data2 ); $this->{LISTCTRL}->SetItem( $id, 2, $data3 ); $hash{$data}{0} = $data; $hash{$data}{1} = $data2; $hash{$data}{2} = $data3; } $this->{LISTCTRL}->Show( 1 ); my( $item ) = Wx::ListItem->new; $this->{LISTCTRL}->SetColumnWidth( 0, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 1, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 2, wxLIST_AUTOSIZE ); my( $topsizer ) = Wx::BoxSizer->new( wxVERTICAL ); $topsizer->Add( $this->{LISTCTRL}, 2, wxGROW ); $topsizer->Add( $this->{LOGWINDOW}, 1, wxGROW ); $this->SetSizer( $topsizer ); $this->SetAutoLayout( 1 ); use Wx::Event qw( EVT_LIST_COL_CLICK ); EVT_LIST_COL_CLICK( $this, $this->{LISTCTRL}, \&OnSort ); $this } sub Cmp { my( $f, $s ) = @_; my( $i1, $i2 ) = ( $hash{$f}{$acol}, $hash{$s}{$acol} ); #print "$f => $s\n"; #print "$i1, $i2\n"; if ($sort eq 'asc') { $i1 < $i2; } elsif ($sort eq 'desc') { $i1 > $i2; } } sub OnSort { my( $this, $event ) = @_; $acol = $event->GetColumn; # use Data::Dumper; # print Dumper(%hash); if ($sort eq 'asc') { $sort = 'desc'; } else { $sort = 'asc'; } $this->{LISTCTRL}->SortItems( \&Cmp ); } package MyApp; use strict; use vars qw(@ISA); @ISA = qw(Wx::App); sub OnInit { my( $this ) = @_; my( $frame ) = MyFrame->new( 'wxPerl ListCtrl Test', 50, 50, 450, 34 +0 ); $frame->Show( 1 ); $this->SetTopWindow( $frame ); 1; } package main; my( $app ) = MyApp->new; $app->MainLoop;
        I figured out a solution, since I too am having problems with it. Here's the code which will now sort strings:
        use Wx; package MyFrame; use strict; use vars qw(@ISA); @ISA = qw(Wx::Frame); use Wx qw(:everything); my %hash = (); my $sort = 'asc'; my $acol = 0; sub new { my( $class ) = shift; my( $this ) = $class->SUPER::new( undef, -1, $_[0], [ @_[1, 2] ], [ @_[3, 4] ] ); $this->{LISTCTRL} = Wx::ListCtrl->new( $this, -1, wxDefaultPositio +n, wxDefaultSize, wxLC_REPORT ); $this->{LISTCTRL}->InsertColumn( 0, "Column 1" ); $this->{LISTCTRL}->InsertColumn( 1, "Column 2" ); $this->{LISTCTRL}->InsertColumn( 2, "Column 3" ); # control hidden to speed up insertion $this->{LISTCTRL}->Show( 0 ); my( $id ); my( $elements ) = 5; foreach ( 1 .. $elements - 1 ) { # WORKS my $nnnn = int(rand(100)); # my $data = int(rand(100)); #my $data2 = int(rand(100)); #my $data3 = int(rand(100)); # DOES NOT WORK my $data = "STRING: " . $nnnn; #my $data = "STRING: " . int(rand(100)); my $data2 = "STRING: " . int(rand(100)); my $data3 = "STRING: " . int(rand(100)); $id = $this->{LISTCTRL}->InsertStringItem( $_, $data ); $this->{LISTCTRL}->SetItemData( $id, $nnnn ); $this->{LISTCTRL}->SetItem( $id, 1, $data2 ); $this->{LISTCTRL}->SetItem( $id, 2, $data3 ); $hash{$nnnn}{0} = $nnnn; $hash{$nnnn}{1} = $data; $hash{$nnnn}{2} = $data2; $hash{$nnnn}{3} = $data3; } $this->{LISTCTRL}->Show( 1 ); my( $item ) = Wx::ListItem->new; $this->{LISTCTRL}->SetColumnWidth( 0, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 1, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 2, wxLIST_AUTOSIZE ); my( $topsizer ) = Wx::BoxSizer->new( wxVERTICAL ); $topsizer->Add( $this->{LISTCTRL}, 2, wxGROW ); $topsizer->Add( $this->{LOGWINDOW}, 1, wxGROW ); $this->SetSizer( $topsizer ); $this->SetAutoLayout( 1 ); use Wx::Event qw( EVT_LIST_COL_CLICK ); EVT_LIST_COL_CLICK( $this, $this->{LISTCTRL}, \&OnSort ); $this } sub Cmp { my( $f, $s ) = @_; my( $i1, $i2 ) = ( $hash{$f}{$acol+1}, $hash{$s}{$acol+1} ); print "$f => $s\n"; if ($sort eq 'asc') { if ($i1 lt $i2) { 1; } } elsif ($sort eq 'desc') { if ($i1 gt $i2) { 1; } } } sub OnSort { my( $this, $event ) = @_; $acol = $event->GetColumn; # use Data::Dumper; # print Dumper(%hash); if ($sort eq 'asc') { $sort = 'desc'; } else { $sort = 'asc'; } $this->{LISTCTRL}->SortItems( \&Cmp ); } package MyApp; use strict; use vars qw(@ISA); @ISA = qw(Wx::App); sub OnInit { my( $this ) = @_; my( $frame ) = MyFrame->new( 'wxPerl ListCtrl Test', 50, 50, 450, 34 +0 ); $frame->Show( 1 ); $this->SetTopWindow( $frame ); 1; } package main; my( $app ) = MyApp->new; $app->MainLoop;
        It's a hack, but it works. This ListCtrl stuff has been driving me nuts!!!!!!
Re: Determing "numeric value" of string?
by kyle (Abbot) on Feb 11, 2009 at 20:19 UTC

    To do this, you'd have to treat the string as a sort of base-n number where n is the number of possible characters you expect to find in the string. If you have flat seven bit ASCII, that's 128 characters. If you have Unicode encoding, it's some crazy huge number. If your alphabet is small, you can map each "letter" to a serial number to use as "digits."

    Strings of even a modest length will be crazy huge when turned to numbers, so I don't think this will be useful for what you're trying to do.

    use List::Util qw( sum ); my $s = 'ook'; my $base = 128; my $e = 1/$base; print sum map { ord() * ($e *= $base) } reverse split //, $s; print "\n"; __END__ 1832939

    Update: Fixed a bug—needed a call to reverse.

      You make a good point...maybe I'll investigate the ListCtrl widget to see if there is a better solution...anyone have any ideas?

      Thanks

Re: Determing "numeric value" of string?
by GrandFather (Cardinal) on Feb 11, 2009 at 20:56 UTC

    How about showing us a little code?

    Maybe you could digest the strings using MD5 or some such and use the "number" returned by the digest in the sort. Of course that doesn't sort them in conventional order, but it is at least sorted.


    Perl's payment curve coincides with its learning curve.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://743135]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (4)
As of 2014-08-30 16:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (293 votes), past polls