in reply to Re: File write
in thread File write

Hello!
Yes, the missing file handle was a silly mistake.
However after the file write I need c.txt to look like this, gramm. category against matched word:
Here noun I am verb this is me Theres advb nowhere else on earth Id ra +ther be

which the this code does not do:
foreach (keys %tagdict){ print CF $tagdict{$_} if exists $tagcorpus{$_}; }

I've tried to do this in another round-about way,but there's
a problem with this is too.Here's the code:
open DF, 'd.txt' or die $!; my %tagdict; while (<DF>) { chomp; my ($word, $cat) = split; $tagdict{$word} = $cat; } while ( ($k,$v) = each %tagdict ) { #print "$k => $v\n"; } close DF; open CF, '+<c.txt' or die $!; my %tagcorpus; while (<CF>) { chomp; my @cwords = split; @tagcorpus{@cwords} = (1) x @cwords; } while ( ($k,$v) = each %tagcorpus ) { #print "$k => $v\n"; } close CF; open CF, '+<c.txt' or die $!; seek CF, 0, 0; # go to start of file truncate CF, 0; foreach $ditem(keys %tagdict){ #print "\n$ditem"; foreach $vitem(values %tagdict){ #print "\n$vitem"; $_ = process($_); #print $_; print CF; print CF " "; foreach $citem(keys %tagcorpus) { #print "\n$vitem"; my $currentposition=tell CF; seek CF,0,1 ; if ($citem eq $ditem){ syswrite CF,"$vitem",4 ; } } } } close CF; sub process{ foreach $key(keys %tagcorpus){ #print "\n$key"; return($key); } } 1;

The problem is in this part:
foreach $key(keys %tagcorpus){ #print "\n$key"; return($key); }

I can't figure out why the print statement keeps printing
the same word as a key value.Towards the top of the program in
while ( ($k,$v) = each %tagcorpus ) { #print "$k => $v\n"; }

the key and value pairs are being printed properly.

If this is solved the file write should work, I have used
this same code elsewhere.What is the problem here?
Thanx.

Replies are listed 'Best First'.
Re: Re: Re: File write
by BrowserUk (Patriarch) on Jun 27, 2003 at 11:53 UTC

    I can't figure out why the print statement keeps printing the same word as a key value.

    The short answer is: Because that is what you asked it to do:)

    A slightly longer and hopefully helpful answer is that the keys function returns the keys from the hash. If you want to print the values from the hash you have two options. You can either use the key to retrieve the value from the hash

    %hash = qw/a 1 b 2 c 3 d 4 e 5/; for $key (keys %hash) { print 'Key:', $key, '=', $hash{ $key }, "\n" } Key: e = 5 Key: c = 3 Key: a = 1 Key: b = 2 Key: d = 4

    This is often done when you want to display the keys and the value as above, or perhaps when you want the values ordered by the keys.

    %hash = qw/a 5 b 4 c 3 d 2 e 1/; for $key (sort keys %hash) { print $hash{ $key }, "\n" } 5 4 3 2 1

    Here, the keys were sort ascending, but the values come out descending because thats the way they are associated.

    However, if you just want to print out the values and don't care about their order, or you want to order them by their own value, not that of their associated keys then you can use the values function instead.

    perl> %hash = qw/a 5 b 4 c 3 d 2 e 1/; for $val (values %hash) { print $val, "\n" } 1 3 5 4 2 for $val ( sort values %hash ) { print $val, "\n" } 1 2 3 4 5

    HTH.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      Hello,
      what I meant was that this bit of code in the
      program(in the subroutine process)
      foreach $key(keys %tagcorpus){ print "\n$key"; return($key); }


      gives this as output(the same word as a key):
      else else else else else else else else else else else else else else


      whereas this bit of code
      while ( ($k,$v) = each %tagcorpus ) { print "$k => $v\n"; }


      prints the key&value pairs properly
      else => 1 on => 1 earth => 1 Here => 1 me => 1 am => 1 rather => 1 this => 1 Theres => 1 Id => 1 I => 1 is => 1 nowhere => 1 be => 1


      but the subroutine process keeps returning only this word: else

      Thanks for the help on hashes anyway.
      I have changed the code and it now works.
      Here is the changed file write portion:
      open CF, '+<c.txt' or die $!; seek CF, 0, 0; # go to start of file truncate CF, 0; foreach $citem(keys %tagcorpus){ #print "\n$citem"; print CF $citem; print CF " "; foreach $ditem(keys %tagdict){ my $currentposition=tell CF; seek CF,0,1 ; if ($citem eq $ditem){ print CF "$tagdict{$ditem}"; } } } close CF;


      This changes c.txt into(gramm. category against matched
      word)
      else on earth Here noun me am verb rather this Theres advb Id I is now +here be


      i.e noun against Here verb against am advb against Id


      Of course the words in the sentence are not properly
      ordered.For this I think we need to extract the keys of
      %tagcorpus in the insertion order and then write onto the
      file.This is what I need to do now :)
      Thanx.

        what I meant was that this bit of code in the program(in the subroutine process)
        foreach $key(keys %tagcorpus){ print "\n$key"; return($key); }

        The reason for the difference between the for version of the loop and the while version is that in the for version, the keys operator generates a list of the keys at the top of the loop, and then gives you the first one of these. Your code print out that (first) key and the returns it to the caller. This terminates the for loop having only iterated once and ignoring all the other keys.

        You always get the same value, because the next time you call the sub, you re-enter the for loop at the top and call the keys function again. It re-builds the list of all the keys and then gives you the first one again. Hence, you always get the same (first) key returned from the sub, each time you call it.

        However, in the while each version of the loop, the each function works in a completely different way. each acts as an iterator. That is to say, the first time you call each it gives you the first key/value pair, but it also remembers which ones it gave you internally, and the next time you call it, it gives you the next key/value pair and again remembers which one it gave you. It continues to give you the 'next' key/value pair each time you call it until it has given you them all, at which point it will give you undef to indicate to you that it has reached the end of the list. The next time after that, it will again give you the 'first' key.

        There are a couple of caveats with this.

        1. 'First' and 'next' in the above descriptions do not relate to any concept of first & next as applied to the order in which you created the keys, nor to any ordering that you should try and predict or that your code should rely upon as it can, and does, vary from version to version of perl.
        2. If you use the each function to step part way through the list of key/value pairs of a given hash and then call the either the keys or values function on that same hash somewhere in else in your code, it will reset the 'memory' of the each iterator and then next time you call it, it will start from the beginning of the list again.
        3. You should also not modify the hash whilst iterating over it with each as this will invalidate the iterators memory of how far it got, but it won't notice and it won't warn you. Eg.
          undef %h; @h{'a'..'m'}=1..13; print each %h, ' - ' for 1..7; # Gives "e 5 - a 1 - m 13 - d 4 - j 10 - l 12 - c 3 -" # The first seven key/value pairs in some order print each %h, ' - ' for 1..7; # Gives "k 11 - h 8 - b 2 - g 7 - f 6 - i 9 - -" # The last 6 + an empty pair to indicate the end of the list undef %h; @h{'a'..'m'}=1..13 print each %h, ' - ' for 1..7; # Gives "e 5 - a 1 - m 13 - d 4 - j 10 - l 12 - c 3 -" The firs +t seven as before @h{'n'..'z'} = 14..26; # Now modify the hash by adding some new stuff # Now continue iterating them from whre we were before print each %h, ' - ' for 1..7; # Gives "p 16 - k 11 - h 8 - g 7 - f 6 - t 20 - i 9 -" # Looks good, no empty pair so it knows there are more # and nothing is duplicated... print each %h, ' - ' for 1..7; # Print the next batch # "e 5 - n 14 - v 22 - m 13 - s 19 - l 12 - c 3 -" Whoops!! # Even though we haven't had the empty pair to indicate the of the lis +t # Were starting to see some elements being repeated. # We've already seen e, m, j, l & c in the first batch. print each %h, ' - ' for 1..7; # Gives "p 16 - b 2 - q 17 - z 26 - o 15 - - w 23 -" NOTE the e +mpty pair! # Now we have reached the end of the list, wrapped and are starting ag +ain # But the first one we get this time is 'w' rather than 'e' that we go +t first time # And it isn't 'a' in either case.

        None of this is a bug! This is all expected behaviour and the anomoly that you perceive is your misunderstanding of the way things work. I'd recommend that you review your understanding by (re-)reading the documentation of perlfunc:each, perlfunc:keys and perlfunc:values.

        A word of caution. If you ever find yourself returning from the middle of a loop within a subroutine, especially unconditionally, you should probably look twice at your code and think if the way you are approaching the problem is the best way. Ocassionally it will be, but most times this is an indication that you should re-think the sub.

        Of course the words in the sentence are not properly ordered.For this I think we need to extract the keys of %tagcorpus in the insertion order and then write onto the file.This is what I need to do now :)

        This is going to be a problem. There isn't any easy way of retrieving the keys or values from a standard perl hash "in there insertion order", and the need to do so usually indiactes that you are using the wrong data structure. However, there are cases (and this may be one of them, but its hard to tell from the snippets of code that you have posted:), where you want the fast lookup afforded by the hash, but you also need to do insertion order retrieveal. In this case, there is a module Tie::IxHash that will allow you to do this. I suggest you follow that link and decide for yourself if this may be useful to you.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller