Home of the Squeezebox™ & Transporter® network music players.
Page 1 of 2 12 LastLast
Results 1 to 10 of 12
  1. #1
    Senior Member
    Join Date
    Apr 2005
    Location
    UK/London
    Posts
    4,133

    Perl and copying hashes from an array

    I would appreciate some extra eyes on this ... as I have been trying all sorts of alternative ways to express things with \ @ {}
    This code is a simplification of what is happening:

    Code:
    use Data::Dumper;
    
    my $dumped;
    
    my %thisProg;
    
    my @names = (
           {name =>'test0'},
    );
    
    push @names, {name =>'test1'};
    
    $thisProg{'name'} = "test2";
    
    push @names, \%thisProg;
    
    my $file_no = scalar (@names);
    
    for (my $i=0; $i < $file_no; $i++) {
          print "$names [$i]{'name'}  is:". $names [$i]{'name'}."\n";
    }
    
    $dumped = Dumper $names[1];
    print("Dump (expect name=>test1): $dumped \n");
    
    $thisProg = $names[1];
    
    $dumped = Dumper $thisProg;
    print("Dump2 (expect name=>test1): $dumped \n");
    
    my $name = $thisProg{'name'};
    
    print("copy back (want test1): $name\n");
    The output from it is:
    Code:
    [0]{'name'}  is:test0
     [1]{'name'}  is:test1
     [2]{'name'}  is:test2
    Dump (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    Dump2 (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    copy back (want test1): test2
    I had expected that the last output would be "test1" as a result of the assignment
    $thisProg = %names[1];
    but it does not seem to work as I thought.
    Last edited by Paul Webster; 2021-02-23 at 11:32. Reason: changed one character - see post that followed
    Paul Webster
    http://dabdig.blogspot.com
    Author of "Now Playing" plugins covering Radio France (FIP etc), PlanetRadio (Bauer - Kiss, Absolute, Scala, JazzFM etc), KCRW, Supla Finland, ABC Australia, CBC/Radio-Canada and RTE Ireland

  2. #2
    Senior Member
    Join Date
    May 2010
    Location
    London, UK
    Posts
    801
    Quote Originally Posted by Paul Webster View Post
    I had expected that the last output would be "test1" as a result of the assignment
    $thisProg = %names[1];
    but it does not seem to work as I thought.
    According to my perl v5.30 your script doesn't run at all:
    Code:
    syntax error at untitled text line 28, near "%names["
    Execution of untitled text aborted due to compilation errors.
    When did it become legal to treat hashes as arrays ?
    (I'm still on v5.8, really).

  3. #3
    Senior Member
    Join Date
    Apr 2005
    Location
    UK/London
    Posts
    4,133
    That is probably the result of my trying everything, everywhere!

    However, changing it to a more correct $ does not resolve things.
    (I'll change it in the original message in case anyone else has a try)
    Paul Webster
    http://dabdig.blogspot.com
    Author of "Now Playing" plugins covering Radio France (FIP etc), PlanetRadio (Bauer - Kiss, Absolute, Scala, JazzFM etc), KCRW, Supla Finland, ABC Australia, CBC/Radio-Canada and RTE Ireland

  4. #4
    Babelfish's Best Boy mherger's Avatar
    Join Date
    Apr 2005
    Location
    Switzerland
    Posts
    20,536
    Quote Originally Posted by Paul Webster View Post
    I had expected that the last output would be "test1" as a result of the assignment
    $thisProg = %names[1];
    but it does not seem to work as I thought.
    What Perl version are you using? Running your code I get:
    Code:
    % perl test.pl 
    syntax error at test.pl line 26, near "%names["
    Execution of test.pl aborted due to compilation errors.
    And there it is, your error. "%names[1]" is an invalid statements: the prefix % is used in hashes, but you want to read an array element. In that case you'd have to use a $: "$thisProg = $names[1];"

    Next issue: confusion about what you're dealing with.

    Code:
    $thisProg = $names[1];
    Here you assign $names[1] to a new variable $thisProg. This is a scalar now containing a hash reference.

    Code:
    my $name = $thisProg{'name'};
    Here you don't read from the above new variable, but from %thisProg, a hash. Because in the above statement you "copied back" to a new variable, the old one didn't change.

    If you added "use strict;" at the top of the script, you'd get more useful hints:

    Code:
    % perl test.pl
    Global symbol "$thisProg" requires explicit package name at test.pl line 28.
    Global symbol "$thisProg" requires explicit package name at test.pl line 30.
    Execution of test.pl aborted due to compilation errors.
    (that's obviously after fixing the first issue)
    Michael

    "It doesn't work - what shall I do?" - "Please check your server.log and/or scanner.log file!"
    (LMS: Settings/Information)

  5. #5
    Senior Member
    Join Date
    Apr 2005
    Location
    UK/London
    Posts
    4,133
    Thanks for the input from you both.

    Revised version ... it seems to work ... but is it OK?

    Code:
    use strict;
    use Data::Dumper;
    
    my $dumped;
    
    my %thisProg;
    
    my @names = (
           {name =>'test0'},
    );
    
    push @names, {name =>'test1'};
    
    $thisProg{'name'} = "test2";
    
    push @names, \%thisProg;
    
    my $file_no = scalar (@names);
    
    for (my $i=0; $i < $file_no; $i++) {
          print "$names[$i]{'name'}  is:". $names[$i]{'name'}."\n";
    }
    
    $dumped = Dumper $names[1];
    print("Dump (expect name=>test1): $dumped \n");
    
    %thisProg = %{$names[1]};
    
    $dumped = Dumper \%thisProg;
    print("Dump2 (expect name=>test1): $dumped \n");
    
    my $name = $thisProg{'name'};
    
    print("copy back (want test1): $name\n");
    output:
    Code:
    test0  is:test0
    test1  is:test1
    test2  is:test2
    Dump (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    Dump2 (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    copy back (want test1): test1
    Paul Webster
    http://dabdig.blogspot.com
    Author of "Now Playing" plugins covering Radio France (FIP etc), PlanetRadio (Bauer - Kiss, Absolute, Scala, JazzFM etc), KCRW, Supla Finland, ABC Australia, CBC/Radio-Canada and RTE Ireland

  6. #6
    Babelfish's Best Boy mherger's Avatar
    Join Date
    Apr 2005
    Location
    Switzerland
    Posts
    20,536
    Correct in what regard? It returns what you expected it to return. And yes, I'd say it does what you told it to do :-). Where do you still have doubts?
    Michael

    "It doesn't work - what shall I do?" - "Please check your server.log and/or scanner.log file!"
    (LMS: Settings/Information)

  7. #7
    Senior Member
    Join Date
    Apr 2005
    Location
    UK/London
    Posts
    4,133
    I still had doubts about the "push" ... so I did some more experimentation and it is now resolved.
    It needed some {} rather than \
    so
    push @names, \%thisProg;
    becomes
    push @names, {%thisProg};
    Without them the test3 below would print "test2" because it was referring to the original location.


    Code:
    use strict;
    use Data::Dumper;
    
    my $dumped;
    
    my %thisProg;
    
    my @names = (
           {name =>'test0'},
    );
    
    push(@names, {name =>'test1'});
    
    $thisProg{'name'} = "test2";
    print("test2: $thisProg{'name'}\n");
    push(@names, {%thisProg});
    
    $thisProg{'name'} = "test3";
    print("test3: $thisProg{'name'}\n");
    
    push(@names, {%thisProg});
    
    my $num = scalar (@names);
    
    for (my $i=0; $i < $num; $i++) {
          print "$names[$i]{'name'}  is:". $names[$i]{'name'}."\n";
    }
    
    $dumped = Dumper $names[1];
    print("Dump (expect name=>test1): $dumped \n");
    
    %thisProg = %{$names[1]};
    
    $dumped = Dumper \%thisProg;
    print("Dump2 (expect name=>test1): $dumped \n");
    
    my $name = $thisProg{'name'};
    
    print("copy back (want test1): $name\n");
    New output:
    Code:
    test2: test2
    test3: test3
    test0  is:test0
    test1  is:test1
    test2  is:test2
    test3  is:test3
    Dump (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    Dump2 (expect name=>test1): $VAR1 = {
              'name' => 'test1'
            };
     
    copy back (want test1): test1
    Last edited by Paul Webster; 2021-02-23 at 23:06.
    Paul Webster
    http://dabdig.blogspot.com
    Author of "Now Playing" plugins covering Radio France (FIP etc), PlanetRadio (Bauer - Kiss, Absolute, Scala, JazzFM etc), KCRW, Supla Finland, ABC Australia, CBC/Radio-Canada and RTE Ireland

  8. #8
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    7,065

    Perl and copying hashes from an array

    Quote Originally Posted by Paul Webster View Post
    I still had doubts about the "push" ... so I did some more experimentation and it is now resolved.
    It needed some {} rather than \
    so
    push @names, \%thisProg;
    becomes
    push @names, {%thisProg};
    Without them the test3 below would print "test2" because it was referring to the original location.


    Code:
    use strict;
    use Data::Dumper;
    
    my $dumped;
    
    my %thisProg;
    
    my @names = (
           {name =&gt;'test0'},
    );
    
    push(@names, {name =&gt;'test1'});
    
    $thisProg{'name'} = "test2";
    print("test2: $thisProg{'name'}\n");
    push(@names, {%thisProg});
    
    $thisProg{'name'} = "test3";
    print("test3: $thisProg{'name'}\n");
    
    push(@names, {%thisProg});
    
    my $num = scalar (@names);
    
    for (my $i=0; $i &lt; $num; $i++) {
          print "$names[$i]{'name'}  is:". $names[$i]{'name'}."\n";
    }
    
    $dumped = Dumper $names[1];
    print("Dump (expect name=&gt;test1): $dumped \n");
    
    %thisProg = %{$names[1]};
    
    $dumped = Dumper \%thisProg;
    print("Dump2 (expect name=&gt;test1): $dumped \n");
    
    my $name = $thisProg{'name'};
    
    print("copy back (want test1): $name\n");
    New output:
    Code:
    test2: test2
    test3: test3
    test0  is:test0
    test1  is:test1
    test2  is:test2
    test3  is:test3
    Dump (expect name=&gt;test1): $VAR1 = {
              'name' =&gt; 'test1'
            };
     
    Dump2 (expect name=&gt;test1): $VAR1 = {
              'name' =&gt; 'test1'
            };
     
    copy back (want test1): test1
    Yes because you would store a reference to the hash in the array. So there is just one unique hash and when you change it, it will be changed for whatever is referencing it (pointing at it). Using {%} creates a copy of the hash which is being pushed then in the array. Just one comment, be aware that simple hash copy does not make deep copies.
    Last edited by philippe_44; 2021-02-23 at 23:52.
    LMS 8.2 on Odroid-C4 - SqueezeAMP!, 5xRadio, 5xBoom, 2xDuet, 1xTouch, 1xSB3. Sonos PLAY:3, PLAY:5, Marantz NR1603, Foobar2000, ShairPortW, 2xChromecast Audio, Chromecast v1 and v2, Squeezelite on Pi, Yamaha WX-010, AppleTV 4, Airport Express, GGMM E5, RivaArena 1 & 3

  9. #9
    Senior Member
    Join Date
    Apr 2005
    Location
    UK/London
    Posts
    4,133
    Regarding deep copy .... thanks.
    I had spotted that when searching for similar code while trying to work out my problem yesterday.
    It is OK for me because I am only pushing relatively simple stuff, including an array of strings that I worked out I had to push [@array] rather than @array for the same reason.
    Paul Webster
    http://dabdig.blogspot.com
    Author of "Now Playing" plugins covering Radio France (FIP etc), PlanetRadio (Bauer - Kiss, Absolute, Scala, JazzFM etc), KCRW, Supla Finland, ABC Australia, CBC/Radio-Canada and RTE Ireland

  10. #10
    Senior Member philchillbill's Avatar
    Join Date
    Jan 2019
    Location
    The Netherlands
    Posts
    642
    https://www2.cs.duke.edu/courses/fal...Cheatsheet.pdf

    I always find this useful to refer to with Perl.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •