2

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 know 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.

brian d foy
134k31 gold badges214 silver badges613 bronze badges
asked Jan 5, 2010 at 14:17
5
  • 2
    What don't you like about [ reverse ...]? Commented Jan 5, 2010 at 14:44
  • 3
    If you want it any cleaner, use Ivan Nevostruev's suggestion. But honestly, the line you've given isn't that bad. I'd worry about something else. Commented Jan 5, 2010 at 14:45
  • @Chris I think your right. I was hoping for an solution that I overlooked. Commented Jan 5, 2010 at 14:48
  • 1
    If I had to reverse a list stored in an array reference and store it in another array reference, I'd do just what you did. Unless you're seeing significant problems with that for your situation, move on in life. :) Commented Jan 5, 2010 at 15:36
  • No significant problems :) I just hoped there would be a better way and curious about other solutions. Moving on... Commented Jan 5, 2010 at 20:32

6 Answers 6

9

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]} ];
}
answered Jan 5, 2010 at 14:19
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, not really what I was looking for, but it does simplify it a bit.
Your second suggestion will result in even more code if you write it all out.
@kemp A clean way to reverse an arrayref.
May be you need to create your own function for this (see update). As far as I know there is no build-in function to reverse array by reference.
@Ivan Your function approach is probably the cleanest way to do the reverse, with the exception that it needs an extra function.
7

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

Comments

6

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.

answered Jan 5, 2010 at 16:40

Comments

2

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.

answered Jan 5, 2010 at 14:41

2 Comments

Sorry, no, I have been programming perl for about 10 years. I'm looking for programmer opinion, knowledge, and experience, not simple answers.
so, don't be sorry. look for your answer.
0

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;
answered Jan 5, 2010 at 15:18

Comments

0

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 });
answered Jan 5, 2010 at 20:10

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.