Searching in Hashes

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Gangreen
    New Member
    • Feb 2008
    • 98

    Searching in Hashes

    There is a hash in my program.
    The problem is I need to search in the hash, but there are some keys that are identical, but I need to get the associated value of all these keys.

    when I do something like

    $value = $hash{ "theKey" };

    obviously I'm only getting the value associated to the first key called "theKey". How can I get the others? Some sort of loop?

    thanks
  • KevinADC
    Recognized Expert Specialist
    • Jan 2007
    • 4092

    #2
    Hashes can not have identical keys. Each key has to be unique. Are you using a hash of hashes or array of hashes?

    Comment

    • Gangreen
      New Member
      • Feb 2008
      • 98

      #3
      Originally posted by KevinADC
      Hashes can not have identical keys. Each key has to be unique. Are you using a hash of hashes or array of hashes?
      Let me give you some mre info; it's an exercise I'm making.

      It's like a webshop which has items, a product code, a price and a quantity.

      I read a file, which holds a 'database' of items for sale and it's structured like this:
      for every item for sale there is a line in the textfile:

      value1|value2|v alue3|value4

      value1 is unique for every item. Call it a productcode or id number.
      anyway due to search querys I will need to be able to get a product code from a title(which is provided by the query).

      so I need a hash which has the names of the objects as keys, and the associated values will be the product codes.

      now let's say there is a book and a dvd for sale with the exact same name I need to be able to get both product codes out of my hash.

      That's the whole problem.

      I have doublechecked my hash, and it has two identical keys after reading the file and creating the hash... I printed them all with a foreach loop.

      p.s it's just a simple hash, no complicated things, I'm new^^

      Comment

      • KevinADC
        Recognized Expert Specialist
        • Jan 2007
        • 4092

        #4
        The same hash can not have two identical keys. Try it and see:

        Code:
        %hash = (
           foo => 1,
           foo => 2,
           foo => 3
        );
        
        foreach my $key (keys %hash) {
           print "$key = $hash{$key}\n";
        }
        I don't know where you are making an error in thinking that your hash does. Post some code so I can take a look at what you are doing.

        Comment

        • Gangreen
          New Member
          • Feb 2008
          • 98

          #5
          [code=perl]
          sub loadInventory{
          open (INVENTORY, $inventoryPath) ;
          $line = <INVENTORY>;
          while ($line){
          @fields = split(/\|/ , $line);
          ...
          %inventoryCodes = ($fields[1],$fields[0],%inventoryCode s);
          ...
          $line = <INVENTORY>;
          }
          }
          [/code]

          the file to be read has got for example these two lines:

          DVD-432|Harry Potter and the Prisoner of Azkaban|25.00|5
          BOOK-432|Harry Potter and the Prisoner of Azkaban|15.00|7

          because of the split: the values are:
          $fields[0] | $fields[1] | $fields[2] | $fields[3]

          so, because of this line:
          %inventoryCodes = ($fields[1],$fields[0],%inventoryCode s);

          i guess this hash will get two pairs, both with the value "Harry Potter and the Prisoner of Azkaban", but they won't have thesame product code...or am I mistaken?

          Thanks for the help btw

          Comment

          • WinblowsME
            New Member
            • Jan 2008
            • 58

            #6
            How about storing and printing the data like the following?

            [CODE=perl]use warnings;
            use strict;
            use Cwd;

            &init;

            sub init
            {
            my %data = ();
            my $directory = &getcwd;

            open ( IN, "$directory/Input.txt" );
            my $line = <IN>;

            while ( $line = <IN> )
            {
            chomp ( $line );

            my ( $type_id, $name, $price, $quantity ) = split ( /\s*\|\s*/, $line );
            my ( $type, $id ) = split ( /-/, $type_id );

            $data{$id}{$typ e}{NAME} = $name;
            $data{$id}{$typ e}{PRICE} = $price;
            $data{$id}{$typ e}{QUANTITY} = $quantity;
            }
            close ( IN );

            foreach my $i ( sort keys %data )
            {
            foreach my $t ( sort keys %{$data{$i}} )
            {
            # if ( $t =~ /DVD/i )
            # if ( $t =~ /book/i )

            if ( $data{$i}{$t}{N AME} =~ /Harry Potter/i )
            {
            print "$i -> $t -> $data{$i}{$t}{N AME} -> $data{$i}{$t}{P RICE} -> $data{$i}{$t}{Q UANTITY}\n";
            }
            }
            }
            }[/CODE]

            Comment

            • KevinADC
              Recognized Expert Specialist
              • Jan 2007
              • 4092

              #7
              Code:
              guess this hash will get two pairs, both with the value "Harry Potter and the Prisoner of Azkaban", but they won't have thesame product code...or am I mistaken?
              "Harry Potter and the Prisoner of Azkaban" is a value, not a key. The key is the product ID. Your code could be written much better.

              Comment

              • Gangreen
                New Member
                • Feb 2008
                • 98

                #8
                @WinblowsME: Thanks, but I'm affraid that is not allowed due to other restrictions..

                @KevinADC: I'm aware my code isn't good ^^ I'm only into perl a couple days now,

                anyway...If Harry Potter and the Prisoner of Azkaban is a value, howcome when I do:

                $productCode = $inventoryCodes { Harry Potter and the Prisoner of Azkaban }

                the $productCode variable is correct? but ofcourse only the DVD-code, and not both (DVD and BOOK)...I'm confused now ^^

                Comment

                • KevinADC
                  Recognized Expert Specialist
                  • Jan 2007
                  • 4092

                  #9
                  Originally posted by Gangreen
                  @KevinADC: I'm aware my code isn't good ^^ I'm only into perl a couple days now,

                  anyway...If Harry Potter and the Prisoner of Azkaban is a value, howcome when I do:

                  $productCode = $inventoryCodes { Harry Potter and the Prisoner of Azkaban }

                  the $productCode variable is correct? but ofcourse only the DVD-code, and not both (DVD and BOOK)...I'm confused now ^^

                  My mistake, I misread the code:

                  %inventoryCodes = ($fields[1],$fields[0],%inventoryCode s);

                  you reversed fields [1] and [0] making field [1] the key and field [0] the value. The fact remains, hashes can not have two identical keys, there is no reason to continue discussing that part of the question. When you build up your hash from the file the last value that was read in from the file that is associated with the key will be stored in the hash. If you need a hash key to have multiple values you have to use more complex data structures, like a hash of arrays or whatever is appropriate.

                  Comment

                  • Gangreen
                    New Member
                    • Feb 2008
                    • 98

                    #10
                    I believe you about the unique key part.

                    Ii'm trying to figure out how I'm gonna bypass that problem. probably by working with arrays, which is easy, instead of hashes, but that will be slow with big files..

                    Do you know any way of creating a hash system in which I can store the names: like "Harry Potter..." and the productcode of the object. With the knowledge that there will be items with identical names but different productcodes AND that I need to be able to find the productcodes of all items mathing a specified name? (because I need to implement a "search" option based on product names)

                    Comment

                    • KevinADC
                      Recognized Expert Specialist
                      • Jan 2007
                      • 4092

                      #11
                      Originally posted by Gangreen
                      I believe you about the unique key part.

                      Ii'm trying to figure out how I'm gonna bypass that problem. probably by working with arrays, which is easy, instead of hashes, but that will be slow with big files..

                      Do you know any way of creating a hash system in which I can store the names: like "Harry Potter..." and the productcode of the object. With the knowledge that there will be items with identical names but different productcodes AND that I need to be able to find the productcodes of all items mathing a specified name? (because I need to implement a "search" option based on product names)
                      Don't be offended, but judging by the code you posted you need to master some basics first. The way you are reading the data in from the file is a bit convoluted and slow, and the way you are building the hash is not correct.

                      Generic example:

                      Code:
                      my %hash;
                      open(FH,'file') or die "$!";
                      while(<FH>) {
                         chomp;
                         my @data = split(/\|/);
                         push @{$hash{$data[1]}},$data[0];
                      }
                      close FH;
                      That will create a hash of arrays from the first two data fields of each line. To access the array that is associated with the hash key (assumes you know the name of the hash key):

                      Code:
                      foreach my $id (@{$hash{'Harry Potter'}}) {
                           print "$id\n";
                      }
                      which is really the same as a regular array with the exception of some extra symbols @{} to dereference the array that the hash key points to.

                      Comment

                      • eWish
                        Recognized Expert Contributor
                        • Jul 2007
                        • 973

                        #12
                        If you plan on having your product line growing quickly, then I would suggest that you use a database to handle your data for you. It would simplify things for you greatly.

                        --Kevin

                        Comment

                        • minowicz
                          New Member
                          • Feb 2008
                          • 12

                          #13
                          Actually, what you are trying to do is not so ill advised as some have tried to make out. It sounds like what you really want to do is search through your database for products that match a given title. A hash is a great way to search for things, but unfortunately, as has been mentioned, the hash keys need to be unique.

                          The first possible work-around for this would be to simply use the product ID as your key. This gets you something unique, but means that to 'search' you'll have to iterate through all the keys and check for a value that matches the title for which you are searching.

                          My suspicion is that you want to avoid such a search by instead creating an index with a hash. The problem of course is that you can't simply use the title as the key to your has and associate the product ID with it since each new occurrence of the same title will result in overwriting the previously associated value.

                          Instead though, what you could do is create what is called a hash of arrays.

                          Rather than simply storing the value in the hash under a certain key, you instead could have each key associated with a reference to an array. Instead of putting the product ID into the value for a given key, you would add it to the array associated with the key. This gives you a hash that looks like this:

                          Code:
                          my %search_index = (
                            'Title One'  => ['book-123', 'dvd-456'],
                          );
                          Then you'll simply be able to look for the key in the has and find out that book-123 and dvd-456 both match that title. A further lookup into the has that uses the product IDs as its keys will give you the full details for either or both of these matches. This scales out fairly well.

                          I'd post some example code, but I'm in a bit of a rush. Still, there are plenty of good guides and chapters in books on hashes of arrays and other data structures. One good place to start is

                          Code:
                          perldoc perldsc

                          Comment

                          • KevinADC
                            Recognized Expert Specialist
                            • Jan 2007
                            • 4092

                            #14
                            Instead though, what you could do is create what is called a hash of arrays.
                            While you explained it in more detail, that is the same suggestion I already made in a previous post. There has been no mention of what he is trying to do to be ill advised that I noticed, it's the way his going about doing it that needs work.

                            Not that there is anything wrong with repeating what others have already suggested, especially since you took the time to elaborate on it more.

                            Hope to see you around here more often.

                            Regards,
                            Kevin

                            Comment

                            • Gangreen
                              New Member
                              • Feb 2008
                              • 98

                              #15
                              Thanks for the help and explanation, I appreciate it.
                              I'm gonna try the hash of arrays

                              thanks

                              Comment

                              Working...