开发者

How can I reverse an array reference and store that in another array reference in Perl?

I have this example:

my $numbers = [ 1, 2, 3, 4, 5, 6 ];
my $newarray = [ reverse @$numbers ];

This example contains some synthetic code to make the $numbers arrayref appropriate for the reverse function. I would like to remove that code and do something more like this:

my $newarray = reverse $numbers;

I kno开发者_如何学Gow this doesn't work, it returns:

)8936f22x0(YARRA

Is there a better way to reverse an arrayref in Perl without changing the first line?

UPDATE:

my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];

The idea is to make the above line of code better.


If you are ok to use array instead of arrayref, then try this:

my @newarray = reverse @$numbers;

Code my $newarray = reverse $numbers didn't work because reverse is called in scalar context, which make it return a string with charactes in reversed order. From reverse manual:

In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order.

If you declare $newarray variable somewhere above you can write it in following way:

## declare $newarray somewhere else
@$newarray = reverse @$numbers;

Update

May be you would like to create your own function:

sub reverse_by_ref {
    return [ reverse @{$_[0]} ];
}


I think the real fundamental issue here is that you're storing $numbers as an array-ref and trying to operate on them as an array. This might be common place but it is not correct. People do this to keep array's consistently in reference form but the right way is to use the native structure rather than a reference to it. In reference form scalar, reverse, pop/push/shift/unshift and all others will require explicit deference to operate on an array. This is common to all languages that permit references to arrays -- look at C's character pointers vs character arrays and things like the sizeof() operator. Really what we're doing here is making use of perl's extremely convenient anonymous array syntax to your own detriment.

It isn't a real problem but there is the minor overhead of the dereference and the almost inescapable visual element of the deference. Now onward to the /right/ answer. There is a modern solution to this and it is with autobox. Autobox provides all types references included with an object-like syntax.

use autobox;
my $arr = [ 1 .. 10 ];
$arr->reverse;

Just to follow-up, the real reason why we have anonymous array syntax is to create deep structures and avoid passing arrays (requires pushing them onto the stack), more so than to create things that should be arrays as array-refs.

  • $foo( [1..100] ) is much faster than $foo( 1..100 )
  • $arr[1] = [1,2,3] is more convenient than @temp = 1,2,3; $arr[1] = \@temp


You've got several options.

Don't try to cram it all on one line:

my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];

Becomes:

my $mails = $mail_api->GetLogSendMail({ customer_id => $id });
@$mails = reverse @$mails;

If GetLogSendMail is foolish enough to return a reference to an array that you shouldn't mess with, then you'll have to modify this slightly to create a new array:

my $inviolate_mails = $mail_api->GetLogSendMail({ customer_id => $id });
my $mails;  @$mails = reverse @$inviolate_mails;

To keep everything on one line, use a subroutine as Ivan Nevostruev suggests:

sub reverse_ref \@ {
    return [ reverse @{$_[0]} ];
}

my $mails = reverse_ref $mail_api->GetLogSendMail({ customer_id => $id });

If you need to do loads of list-ops on array refs, consider making a library:

package ArrayRef::Util;
# boiler plate skipped.

sub reverse_ref \@ {
    return [ reverse @{$_[0]} ];
}

sub push_ref \@\@ {
    push @{$_[0]}, @{$_[1]};
}

# and so on

Finally, Evan Carroll's autobox suggestion helps too:

use autobox;

my $mails = [ $mail_api->GetLogSendMail({ customer_id => $id })->reverse ];

See Should I use autobox in Perl? for more info on autobox.


did you looking for something like this:

#!/usr/bin/perl

$myNames = ['Jacob', 'Michael', 'Ethan', 'Andrew'];
@reversedNames = reverse(@$myNames); 

print @reversedNames;

take a look at this tutorial.


i don't know if you have control over the original object's source, but if you do, what about adding a ->reverse method to that package?

my $mails = $mail_api->GetLogSendMail({ customer_id => $id })->reverse;


Two questions:

  1. How much control do you have over whatever object $mail_api is?
  2. Do you really need $mails to be a reference rather than an actual array? Why so?

If the answer to 1 is "some" and 2 is "no", then change the GetLogSendMail method to return a list instead of an array reference. Then your code becomes a straightforward

my @mails = reverse $mail_api->GetLogSendMail({ customer_id => $id });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜