I am trying to use a Hash that has 2 values per key. I need to sort on the 2nd value (a number), then delete all of the 2nd number values in the Hash - all the while keeping the sorted numeric order of the Hash.

I am currently getting a "can't coerce array into hash" (inside the subroutine below).

Here is what I have so far: ------------------------------------------------------------------ #!/usr/bin/per -w

The construct inside the sub is called a Schwartzian Transform, after Randal L. Schwartz. I'll try to walk you through it.

-- Starting from the bottom, the keys in %rules are taken as input to a map (the line above). -- Inside the map the keys from %rules are stored in $_. We now create an anonymous array with two elements. The second element is the numbers 1,2,3 from the hash. The first element is also an anonymous array with two elements. -- Move up a line, and the freshly constructed anonymous array is passed to a sort. We want to sort on the second subelement, hence we dereference to [1]. -- The sorted array is returned to yet another map. This one is returning only the first element, while the second is discarded. Remember, that first element was also an anonymous subroutine with two elements. That is returned from the sub.

In the for-loop, $x will be a reference to an anonymous array, we dereference it to get the values we wanted.

Re: [Karazam] Manipulating a Hash with keys that have more than one value

Thank you very much!

What you did works well though I also have a need to make sure that I don't get 2 rulenumbers of the same value.

I can check earlier in my script but was wondering if there is a way inside the Schwartzian Transform? Maybe a check from the sort function output to a variable and then checking that for a rulenumber of the same value?

# need to store each new anonymous array record (1 or more arrays) in the HoA here ... is that already being done in the next line ? # add key and values to anonymous array ( HoA ) $sRules{$file} = [ $data, $rulenumber ];

Some of the syntax questions I have now are related to using references to the original %rules hash through the subroutine calls.

I was under the assumption that when I reference a hash through subroutine calls that all the references to the same hash would update that hash. Not what I am seeing. Syntax related again? Not so sure. Seems like a local/scoping issue.

I am also having a problem verifying the current data in the updating $file key data in the HoA in the foreach $file loop near the top of this listing. (attempted to use print Dumper...)

I then need to do the &get_sorted_rules( $sRules ); call with all the collected rules in the HoA.

Lastly, I need to do the rules sort with the $rulenumber in the HoA, then remove it and store the remaining data in the HoA so I can use the %rules hash in the while loop near the top of the listing.

Re: [spuds] Manipulating a Hash with keys that have more than one value

Umm well, you have not exactly implemented my suggestion, at least not how I meant it. I merely suggested that you put an extra dollar sign at this line to dereference the hashref. (Maybe its typographically hard to see, but it's dollar-dollar-sRules):

Code

$$sRules{$file} = [ $data, $rulenumber ];

Did you try to run the code with only that change, and what happened?

Instead you are now creating a new hash, not a hash ref, inside the subroutine:

Code

my (%sRules) = %{ (shift) };

Maybe that's intentional, but weren't you concerned that the original hash didn't get updated?

Re: [Karazam] Manipulating a Hash with keys that have more than one value

Hi,

I actually did implement the change you suggested (and it worked) but I saw another example on how to pass the hash from sub to sub so I am using that. Just passing the hash by reference, using 'shift' for the first time, within the subs.

I thought using 'shift' would help with some of the other errors I was seeing (strict global hash ones). Seemed to help.

The current error is attempting to find an array ref for $arrayRef and it's getting a string. I have tried declaring the $arrayRef as a ref like $arrayRef = []; but no luck.

Re: [spuds] Manipulating a Hash with keys that have more than one value

Hmm, well that error occurs when you try to pass an array or hash as argument to a subroutine. But I see no more place where that might happen in your code, if you took care of those two you describe.

I have taken the liberty of creating a version of your code that I can run on my machine, with a bit of cleaning up of variable names etc. You can compare it to what you got, hopefully it will help you pinpoint the problem. The part in get_rules that populates the hash will be different from yours of course.

Re: [spuds] Manipulating a Hash with keys that have more than one value

Hi,

I got the script to work using your latest source but see that the %seen hash's array reference is the only time the input rules are in order.

The orginal %rules hash is really what I want updated to the sorted order of rules. (minus all the rulenumbers)

I see when I put a print Dumper call in after the get_rules(\%rules) call that I have the orginal rules in un-sorted order.

When I try to print out all the contents of the anonymous array here:

Code

print "$aref->[0]\t$aref->[1]\n";

I get the sorted data that I need for my now wanted standard key-value only %rules hash. Can I just copy these two values (filename key and contents value) into my %rules hash, one rule at a time similar to this here?

Code

$href{$aref->[0]} = {$aref->[1]};

Is the %seen hash a special hash in perl? Guessing no, just a meaningful name given to this local scalar.

Re: [spuds] Manipulating a Hash with keys that have more than one value

Since you are using references to %rules, that hash will hold the result of your operations. However, a hash is by its nature not sorted. That is, you don't get things out in the same order as you put them in. That's how hashes work. If you want to use the sorted data further, you need to put in a structure that preserves order, that is, an array. So, try this:

I don't see the problem but when I run my source (all of it) and use the exact same subroutine source (as above) I am seeing my local $aref set to 1 the first time in the loop, not what it should be, an ARRAY(memory location) reference.

I printed out the scalar $aref in both your code and my code (copied from you).

For what's it worth, the ends with this error:

Can't use string ("1") as an ARRAY ref while "strict refs" in use at ... line 279

Here is what I am using:

Code

for my $aref ( sort_rules($href) ) 273 { 274 print "the number of times thru this for loop $count\n";

Re: [spuds] Manipulating a Hash with keys that have more than one value

Quote

Any ideas on why my $aref is automatically set to 1 the first time

No, that's strange. But if you still get the "Can't use string ("1") as an ARRAY ref" message, my guess is that there's still some problem with passing references.

About the hash content... It looks weird, doesn't it? There's one value in $VAR1, which is then repeated in $VAR2 together with another value in the same array element, and with a linebreak after it? And why the hash sign? Looks like it's been created this way:

Re: [spuds] Manipulating a Hash with keys that have more than one value

The %rules hash output from your source ... only change I made is to populate the test data there exactly like I did in my script, using:

$rules{$rulekey1} = [ $contents1, $ruleNum1 ];

Both your source and my source scripts take there input the same way (line above), show the EXACT same hash when I do a print Dumper(%rules) at the same point the scripts, but yours run without any array ref "1" error.