Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2011
    Posts
    57
    Rep Power
    4

    Remove Duplicates


    What is the easiest way to throw out duplicate values in a hash?
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    71
    Rep Power
    2
    Make the values keys in another hash.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2012
    Posts
    832
    Rep Power
    496
    Yes, keys of a hash cannot have duplicates. So duplicate values will be thrown away if you make every value a key in another hash, and then reverse the process.

    Actually, using hash keys to remove duplicates from a list is very idiomatic in Perl.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2011
    Posts
    57
    Rep Power
    4
    Thanks, I used the reverse function twice it the duplicates have been thrown out. Just one problem, I'm creating a numbered menu and my numbers were thrown out as well causing the numbers to be out of order. I think I can just pass the values of my original hash into a new hash and start numbering again to fix this. Does that sound right?
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2012
    Posts
    832
    Rep Power
    496
    Did not quite understand your problem, but an adequate sort on your data should probably to the job.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2011
    Posts
    57
    Rep Power
    4
    Originally Posted by Laurent_R
    Did not quite understand your problem, but an adequate sort on your data should probably to the job.
    Mu hash is a menu where the number is the key and the choice is the value. If i have the following:

    Key Value
    1. Joe
    2. Dad
    3. Mom
    4. Joe
    5. Mom

    After I reverse the hash twice to get rid of the duplicates my menu looks like this:

    Key Value
    2. Dad
    4. Joe
    5 Mom

    I want the 2nd menu to be numbered 1, 2 and 3.
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2012
    Posts
    832
    Rep Power
    496
    You are never guaranteed that a hash will give you the data in a given order. The order will always seem "random" (it is not actually random, but looking as if it were random).

    The solution is simply to sort the keys.

    Quick example under the Perl debugger:

    Initial assignment of a hash:
    Code:
    DB<3> %hash = (1=>'jan', 2=>'feb', 3=>'mar');
    Printing the hash keys and values:

    Code:
      DB<9> print "$_: $hash{$_} \n" foreach keys(%hash);
    1: jan
    3: mar
    2: feb
    As you can see, the data elements do not come in the order in which they were entered.

    All I need to to is to sort the keys before using them:

    Code:
      DB<10> print "$_: $hash{$_} \n" foreach sort keys(%hash);
    1: jan
    2: feb
    3: mar
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    929
    It sounds like you want an array rather than a hash.

    Code:
    F:\temp>cat x.pl
    use List::MoreUtils 'uniq';
    
    @values = qw/ abc abc def ghi def /;
    
    while ( ($index,$value) = each @values ) {
        printf "%d. %s\n", $index + 1, $value;
    }
    
    print "--Removing Duplicates--\n";
    
    @values = uniq @values;
    
    while ( ($index,$value) = each @values ) {
        printf "%d. %s\n", $index + 1, $value;
    }
    
    
    F:\temp>perl x.pl
    1. abc
    2. abc
    3. def
    4. ghi
    5. def
    --Removing Duplicates--
    1. abc
    2. def
    3. ghi
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
    Maybe we should take a step back and have you show us how you're building the hash so that we can show you how to alter it to avoid the duplicates.

    We may need to see the whole script so that we can see the overall context.
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2011
    Posts
    57
    Rep Power
    4
    This works but i'm sure I over coded it. I have a tendency to do that.

    Code:
    #!/usr/perl5/bin
    
    my ($filename, $array, $choice);
    my (@array, @file_array);
    my $key = 1;
    my %file_hash = ();
    
    do
    	{
    		print "Please enter a file name: ";
    		chomp ($filename = <STDIN>);
    		push (@array, $filename);
    		
    		
    
    	}while ($filename ne 'q' && $filename ne 'Q'); 
    	
    pop @array;
    
    foreach $array (@array)
    	{	
    		$file_hash{"$key"} = $array;
    		$key = $key + 1;
    	}
    
    	%file_hash = reverse %file_hash;
    	%file_hash = reverse %file_hash;
    
    foreach $key (sort {$a<=>$b}keys %file_hash)
    {
      push (@file_array, $file_hash{$key})
    }
    
    my $x = 1;
    foreach $file_array (@file_array)
    	{
    		print "$x. $file_array\n";
    		$x++;
    	}
    
    print "Please enter a choice: ";
    chomp ($choice = <STDIN>);
    
    print "$file_array[$choice - 1]\n";
    This is just the piece of code that wiull handle the file list and not the complete script. I'm a novice and like to code in pieces to verufy things work then i patch the complete script together. This code will print the menu and the users choice dependent on the number that is sleected. Is there an easier way?

    Can someone explain this to me:
    Code:
    foreach $key (sort {$a<=>$b}keys %file_hash)
    Why does the $a<=>$b sort the hash numerically?
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    71
    Rep Power
    2
    Well you have to understand that the sort function uses the global variables $a and $b for comparing and in your example, $a and $b are used to sort the numeric keys which are compared with the spaceship operator(a numeric comparison operator).

    You really should look up the sort function here for a better explanation:

    http://perldoc.perl.org/functions/sort.html
    http://www.misc-perl-info.com/perl-sort.html
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
    I agree with OmegaZero. A hash is the wrong data structure for this purpose. Just use the array that you already have and base the option number off of the array index + 1.

    You should change the names of your vars. Var names should always reflect the data that they hold. A var name of '@array' tells me nothing about what it holds.

    Personally, I'd use the Term::Prompt module to handle the prompting for user input and I'd probably use the Term::Menu module to display the menu choices.

    Term::Prompt - Perl extension for prompting a user for information
    Term::Menu - Perl extension for asking questions and printing menus at the terminal

    However, your instructor might see that as overkill for this assignment.

    You should add the following 2 pragmas, which should be in every Perl script you write.
    Code:
    use strict;
    use warnings;
  24. #13
  25. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
    Here's an example using Term::Prompt

    Code:
    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use Term::Prompt;
    
    my @filenames;
    
    while (1) {
        my $answer = prompt('x', "Please enter a file name: ", 'q to quit', '');
        last if lc $answer eq 'q';
        push @filenames, $answer;
    }
    
    print $/ x 3;
    
    my $choice = prompt(
                'm',
                {
                    title       => 'File Listing',
                    prompt      => 'Please select a file: ',
                    items       => \@filenames,
                    cols        => 1,
                    separator   => '[^0-9]+',
                },
                '',
                ''
    );
    
    print $filenames[$choice], $/;
  26. #14
  27. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2012
    Posts
    832
    Rep Power
    496
    Now that you tell more about what you want to do, I fully agree that an array would be more appropriate than a hash for storing your data.

    If you can use the List::MoreUtils uniq function, this will remove the duplicates from your array. If this is a home-work assignment, your instructor might desire that you remove duplicates by yourself rather than using an off-the-shelf module, in which case a hash could be use as a temporary side aid to discard duplicates.

    Assuming you can't use external modules, I would rewrite the relevant part of your code as follows (untested):

    Perl Code:
    # ...
    my %seen_file_names; # this hash will make it possible to discard existing file names
    while (1) {
         print "Please enter a file name: ";
         chomp ($filename = <STDIN>);
         last if $filename =~ /q/i; # exit the loop if user entered "q" or "Q"
         next if exists $seen_file_names{$filename}; # removes duplicates even before putting them in the @files array
         push (@files, $filename);
         $seen_file_names{$filename} = 1; # keeps track of seen file names
    }
    # ... do the printing


    The %seen_file_names hash keeps track of the entered values and enables you to remove duplicates even before they are inserted into the @file array.
  28. #15
  29. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2011
    Posts
    57
    Rep Power
    4
    Thanks a lot for the help folks, I try some of this stuff out and see how it goes.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo