Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
I wish to associate a list of coordinates with a list of zones. The zones take the following form -
B1, B2, B3, BR4, I22, IJ1, IJ17....etc.
The coorinates take the form - 1:23,7:59. I was thinking of storing the coorinates as a four dim array - [a1,a2,b1,b2] = [1,23,7,59]. Each zone has a abritary number of coordinates associated with it, such as B1 = [11,21,3,59],[1,23,7,51],[9,2,11,9].

How would I declare a hash to store this type of data? I'd like to add the coordinates on the fly, something like -

for($a1=0;$a1<60;$a1++){ for($a2=0;$a2<60;$a2++){ for($b1=0;$b1<60;$b1++){ for($b2=0;$b2<60;$b2++){ $zone = Get_zone_for_this_coordinate($a1,$a2,$b1,$b2)}; Add_this_coordinate_to_the_hash_for_hash_member_$zone; } } } }
How might I do this?
Thanks.

edited: Sat Nov 15 16:55:49 2003 by jeffa - formatting, code tags

Replies are listed 'Best First'.
Re: Hashing multiple items
by Art_XIV (Hermit) on Nov 15, 2003 at 18:23 UTC

    I suspect that you really want to store the coordinates as a four-element array as opposed to a 4-dimension array. The following might serve as an executable example of what you want:

    use strict; use Data::Dumper; my %zones; while (<DATA>) { chomp; my ($zone, $a1, $a2, $b1, $b2) = $_ =~ /(\w+) = (\d+),(\d+),(\d+),(\d+)/; #append an anonymous (coordinate) array on to the #anonymouse array that is the value for each hash #key in %zones hash. push @{$zones{$zone}}, [$a1, $a2, $b1, $b2]; } print Dumper(%zones); __DATA__ B1 = 11,21,3,59 B2 = 1,23,7,51 B1 = 9,2,11,9 B2 = 1,23,7,59 B3 = 3,92,12,13 B1 = 2,2,18,50
    Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
      Cool,thats what I'm lookin' for
Re: Hashing multiple items
by delirium (Chaplain) on Nov 15, 2003 at 17:56 UTC
    I wouldn't take up a lot of memory with a giant hash of every possibility if I could avoid it. Would it be possible to have a smaller hash or array of the zone ranges and some if statements to figure out what zone a given coordinate is in when you need it?

    my %zones; $zones{B1} = [1,23,7,59]; my @this_coord = (5, 7); my ($x, $y) = @this_coord; while (my ($zone, $rng) = each %zones) { print "Zone is $zone\n" if $$rng[0]<=$x && $$rng[1] >=$x && $$rng[2]<=$y && $$rng[3]>=$y; } __OUTPUT__ Zone is B1
Re: Hashing multiple items
by batkins (Chaplain) on Nov 15, 2003 at 17:27 UTC
    I'm not totally sure I understand the question, but what if you just make the coordinates into a string and use them as a key for the hash?
    my ($coord1, $coord2); $hash{$coord1 . "," . $coord2} = 'value';
    Are you sure it was a book? Are you sure it wasn't.....nothing?
      Actually, perl has a built-in facility for this... if you simply say:
      $hash{$coord1,$coord2} = $value;
      then perl automatically constructs a hash key as:
      $key = join($;, ($coord1, $coord2));
      using $;, the "subscript separator" perl variable. The default value of which is octal 034, the control character "field separator". This isn't quite a perfect solution if your variables can store arbitrary binary data... but, in general, you're pretty safe against occurences of this character occuring in your data. You can perldoc perlvar for more details.

      ------------
      :Wq
      Not an editor command: Wq
        I actually want to do thngs the other way around. I want to have the zone as the key. So that I could say, print out out all the coorsinates in zone B1. Doing this -
        $coordinates{$zone} = $a1,$a2,$b1,$b2)
        will only allow my to save one coordinate for a particular zone. How do I save an arbitary bumber of coordinates for each zone?
Re: Hashing multiple items
by pg (Canon) on Nov 15, 2003 at 19:13 UTC
    "How would I declare a hash to store this type of data?"

    No, you don't declare the internal structure of the hash, whatever how complex it is, the only thing you need to declare is that it is a hash (hash ref). The actual structure is resolved on fly, as you assigning (linking) entities to the hash or any of its sub-structures.

    This is not only true to Perl. Imaging that you are creating a tree in c or Java. You don't need to declare what will be linked to the tree. It could be any entity. In c, it could be void *, in Java, it could be Object. In Perl, it is a ref to something (or a scalar).

    Only you care what it is, as when you retrieve it, you have to tell the computer how to cast it, whether it's a scalar, scalar ref, array ref, hash ref...

Re: Hashing multiple items
by Anonymous Monk on Nov 15, 2003 at 18:22 UTC
    >>Use an anonymous array as value:

    >>$coordinates{$zone} = $a1, $a2, $b1, $b2 ;

    >>Don't forget to dereference it when you read your coordinates back out:
    >>($a1, $a2, $b1, $b2) = @{$coordinates{$zone}}
    This only allows one coord per zone, does it not? Is there a way of pushing the coordinates into $coordinates{$zone}?
    I supply a coordinate and I get a zone in return, there are many different zone types returned. I'd like to be in a position to plot out on a bitmap where each zone is located. To do this, I'll need to store the coordinates for each zone.
Re: Hashing multiple items
by michaelg (Beadle) on Nov 16, 2003 at 14:52 UTC
    Hi,
    If I got you correctly , you might consider somthing like this.
    let say you read the zones and coordinates from file of similar
    structure:
    #Zone #coordinates
    aaa 1.5 2.3 77 51
    bbb 2 -9 3 12
    my %coord = ();
    while(<IN>){
    my @temp = split(/\s+/);
    $coord{$temp[0]) = join(':',$temp[0],$temp1 ... );
    }

    Now you have your list in one pass , and you can search
    your hash in single entry.
    for example:
    if(defined($coord{'aaa'}{
    print_co($coord{'aaa'});
    . . .
    }
    I hope it is good for you
    michaelg