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


Hi Monks,

I know the following works:
($record[0]->{bytes}, $record[1]->{bytes}) = get_bytes(2);

get_bytes is a function which returns an array,
whose length is equal to the argument passed to it.
I use the list assignment feature to populate elements
of @record

Now i need get_bytes to accept a variable.
So basically what i need is some way to specify a
variable number of elements in the LHS.

This works:
@tmp = get_bytes($num); for ($i=0;$i<scalar(@tmp);$i++) { $record[$i]->{bytes} = $tmp[$i]; }

Is there any way, i can eliminate the use of
the @tmp array?

Thanx

--
arc_of_descent

Replies are listed 'Best First'.
Re: variable list assignment
by thpfft (Chaplain) on Aug 03, 2002 at 12:01 UTC

    If you really don't like the temporary array - doesn't seem so bad to me - you could use something like:

    my $i = 0; # or whatever $record[$i++]->{bytes} = $_ for get_bytes($num);

    or perhaps, if you're just building the list:

    push @record, map { {bytes => $_} } get_bytes($num);

    but that won't be much good if you're working with an existing data structure. In that case i don't see a way of shrinking it to one line - and suspect that even if you find one, you'd regret the obfuscation later.

    update just tried mr robot's solution and found, to my surprise, that the double curlies aren't required. I would have expected

    @a = map { k => $_ } (1..3);

    to give you (k,1,k,2,k,3), but no: it creates an array of hashrefs. so either that isn't a block at all - but where's the comma? - or there is such a thing as hash context after all. nice bit of dwimming. still borks any other key that previously existed in the hash, though.

    update^2 don't know what i was thinking there. sauoq is quite right. odd that i remember it working, but clearly it doesn't :(

      Here it is in one line, but this has the (unfortunate side effect/added feature) of choping @array to $n entries.
      use Data::Dumper; my @array; my $n = 10; sub get_bytes { map {rand($_)} 1..$_[0] } $array[$_]->{bytes} = 'fake' for (1..$n); @array = map {$array[0]->{bytes}=$_;shift @array} get_bytes($n); print Data::Dumper::Dumper(\@array);
      update just tried mr robot's solution and found, to my surprise, that the double curlies aren't required. I would have expected

      Actually, you missed a comma that impossiblerobot's code contained. His code was:

      my @record = map { bytes => $_ }, get_bytes($num);
      and that comma between the arguments to map makes map interpret the first argument as an EXPR not a BLOCK.

      BTW, my perl (5.6.1) chokes on the code in your update:

      perl -e '@a = map {k => $_} (1..3)' syntax error at -e line 1, near "}("
      -sauoq
      "My two cents aren't worth a dime.";
      
Re: variable list assignment
by impossiblerobot (Deacon) on Aug 03, 2002 at 20:41 UTC

    Is this what you're looking for?

    my @record = map { bytes => $_ }, get_bytes($num);

    Impossible Robot
Re: variable list assignment
by mephit (Scribe) on Aug 03, 2002 at 19:15 UTC
    I thought of something that *should* work, but I just can't come up with the code. Push a reference to each variable you want to assign to ($records[n]->{bytes}) onto an array and use that as the left hand side. Here's my code and its output:
    my $num = 4; my @records = ( { bytes => 'foo0'}, { bytes => 'foo1'}, { bytes => 'foo2'}, { bytes => 'foo3'}, ); my @results; for (1 .. $num) { push (@results, [ $records[$_]->{bytes} ]); } @results = get_bytes($num); print Dumper (\@records); sub get_bytes { my $num = shift; my @ret; push (@ret, $_) for 1 .. $num; return @ret; } -------------- $VAR1 = [ { 'bytes' => 'foo0' }, { 'bytes' => 'foo1' }, { 'bytes' => 'foo2' }, { 'bytes' => 'foo3' }, {} ];
    Notice the extra anonymous hash tacked onto the end of the (otherwise unchanged) @records array after calling get_bytes() Hmm, something tells me I would need to dereference each element in @results before calling the sub, but I'm stuck. Anybody have any ideas, or is my thinking just Not Good in this case?

    --

    There are 10 kinds of people -- those that understand binary, and those that don't.

Re: variable list assignment
by uri (Acolyte) on Aug 04, 2002 at 07:17 UTC
    $i = 0; $record[$i++]->{bytes} = $_ for get_bytes($num);
Re: variable list assignment
by Courage (Parson) on Aug 03, 2002 at 11:08 UTC
    $record[$_]->{bytes} = [get_bytes($num)]->[$_] for 0..$num;
    but you'll better not use this, because get_bytes will be invoked $num times! And this is really ineffective.

    addition:
    but your three lines of code next to @tmp assignment better written as:

    $record[$_]->{bytes} = $tmp[$_] for 0..$#tmp;

    Courage, the Cowardly Dog


      And this is also not what i want. :-)
      get_bytes should be invoked only once

      Thanx

      --
      arc_of_descent

        I see your point, and can understand a situation when get_bytes gets bytes from file and it is wrong to call it more than once. But anyway, as you did not specified that restriction (also performance considerations were not mentioned), my answer formally should fit...

        Courage, the Cowardly Dog

Re: variable list assignment
by arc_of_descent (Hermit) on Aug 04, 2002 at 10:48 UTC