#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Posts
    55
    Rep Power
    14

    Sorting a hash by value


    Hello,

    I'm able to sort an array by value

    PHP Code:
    foreach $key (sort sortvaldec (keys(%tab))) {
       print 
    "MAC=$key Number=$tab{$key}\n";
    }

    sub sortvaldec $tab{$b} <=> $tab{$a}; } 
    But I would like to pass an argument to sortvaldec to make it more dynamic

    PHP Code:
    foreach $key (sort {sortvaldec(%tab)} (keys(%tab))) {
       print 
    "MAC=$key Number=$tab{$key}\n";
    }

    sub sortvaldec my (%h); (%h) = @_;  $h{$b} <=> $h{$a}; return (%h); } 
    The hash table is sent to the function and it should be returned sorted. However this doesn't work.

    Does anyone know what's wrong with it ?
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Apr 2009
    Posts
    2,231
    Rep Power
    1296
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Posts
    55
    Rep Power
    14
    Originally Posted by FishMonger
    Hello,

    I have read it but haven't been able to solve my problem. I want to write a generic code.

    PHP Code:
    # prints tab1 sorted by values
    printhashsorted(%tab1);
    # prints tab2 sorted by values
    printhashsorted(%tab2);

    sub printhashsorted
    {
      
    my (%t);
      
    my ($a,$b,$k);
      (%
    t) = @_;
      foreach 
    $k sort $t{$b} <=> $t{$a} } (keys (%t))) {
        print 
    "MAC=$k Number=$t{$k}\n";
      }

    The result is unsorted


    If I write the code globally
    PHP Code:
    foreach my $key sort $tab1{$b} <=> $tab1{$a} } keys %tab1) {
        print 
    "MAC=$key Number=$tab1{$key}\n";

    The result is sorted


    Full script for test
    PHP Code:
    #!/usr/bin/perl
    use strict;

    my %tab1 = ("00:04:a5" => "3""00:80:9f" => "2""00:11:88" => "4""00:21:5e" => "1");

    foreach 
    my $key sort $tab1{$b} <=> $tab1{$a} } keys %tab1) {
        print 
    "Test1: MAC=$key Number=$tab1{$key}\n";
    }

    print 
    "\n\n";
    printhashsorted(%tab1);

    sub printhashsorted
    {
      
    my (%t);
      
    my ($a,$b,$k);
      (%
    t) = @_;
      foreach 
    $k sort $t{$b} <=> $t{$a} } (keys (%t))) {
        print 
    "Test2: MAC=$k Number=$t{$k}\n";
      }

  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Apr 2009
    Posts
    2,231
    Rep Power
    1296
    Your problem is caused by declaring $a and $b as lexicals. Don't do that!

    $a and $b are built-in globals specifically used in sort routines. You do not need to, nor should you, declare them as lexicals for use in sorting.

    If you had enabled warnings (via the warnings pragma) perl would have told you about the problem. You would have received a number of warnings like:
    Use of uninitialized value $b in hash element at ....
    Use of uninitialized value $a in hash element at ....
    Here's the corrected version.
    Code:
    #!/usr/bin/perl
    
    use warnings;
    use strict;
    
    my %tab1 = ("00:04:a5" => "3", "00:80:9f" => "2", "00:11:88" => "4", "00:21:5e" => "1");
    
    foreach my $key ( sort { $tab1{$b} <=> $tab1{$a} } keys %tab1) {
        print "Test1: MAC=$key Number=$tab1{$key}\n";
    }
    
    print "\n\n";
    print_hash_sorted_by_value(%tab1);
    
    sub print_hash_sorted_by_value
    {
        my %t = @_;
        #my ($a, $b);
        
        foreach my $k ( sort { $t{$b} <=> $t{$a} } (keys (%t))) {
            print "Test2: MAC=$k Number=$t{$k}\n";
        }
    }
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Apr 2009
    Posts
    2,231
    Rep Power
    1296
    As an OT note, IMO it's better (more efficient) to store MAC addresses as integers and convert them as needed when outputting them.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Posts
    55
    Rep Power
    14
    Thank you FishMonger for your answer and for your suggestions.
    I'll use warnings for now.

    Just a question, how can I store a MAC as an integer since it has letters in it.
    I would have thought that I can store it either as a string or binary (if I convert it in binary).

    Regards
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Regular (2000 - 2499 posts)

    Join Date
    Apr 2009
    Posts
    2,231
    Rep Power
    1296
    A MAC address is a 48bit integer normally displayed as 6 hex numbers.

    I store this data in mysql. Here's a portion of the table definition.
    Code:
    Create Table: CREATE TABLE `devices` (
      `IP` int(10) unsigned NOT NULL,
      `MAC` bigint(19) unsigned NOT NULL,
    Here's an example query.
    Code:
    mysql> select IP as IP_int, MAC as MAC_int, inet_ntoa(IP) as IP, hex(MAC) as MAC from devices order by MAC desc limit 1\G
    *************************** 1. row ***************************
     IP_int: 176173569
    MAC_int: 277807422308165
         IP: 10.128.50.1
        MAC: FCAA14B8FF45
    1 row in set (0.00 sec)
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2003
    Posts
    55
    Rep Power
    14
    Hello FishMonger,
    Thank you very much for your help.
    Have a nice week

IMN logo majestic logo threadwatch logo seochat tools logo