http://qs321.pair.com?node_id=564363

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

Is there an easy|elegant|straightforward way to reorder an array? I need to take a each array of an AoA and reorder it to a specific order. An example:

@orig_array = qw(0 1 1 0 1 0 0 0 1 1 1 0 0 0 0); @new_index_order = qw(8 3 4 9 11 6 7 0 14 10 1 12 2 5 13);
What I want is to put @orig_array into a new array, based on the index order from @new_index_order.

All I can think of is to create a new array with placeholder values, and run through @new_index_order, copying the indexed values from @orig_array left-to-right into the new array, replacing the placeholders. This seems clunky to me, however. Anyone else have a suggestion? Thanks.

Replies are listed 'Best First'.
Re: Reordering Arrays?
by johngg (Canon) on Jul 28, 2006 at 14:52 UTC
    Note that there is a difference in meaning between davorg's reply and BrowserUk's which depends on whether you slice the new or the original array. The following illustrates this

    use strict; use warnings; my @list = qw(zero one two three four); print qq{@list\n}; my @newOrder = (1, 3, 4, 0, 2); my @newList; @newList[@newOrder] = @list; print qq{@newList\n}; @newList = @list[@newOrder]; print qq{@newList\n};

    This produces

    zero one two three four three zero four one two one three four zero two

    It is difficult to tell one zero or one from another, hence the change in list values :)

    Cheers,

    JohnGG

    Update: Here is a clearer explanation of what is happening

    This code @newList[@newOrder] = @list; Means:- $newList[1] receives $list[0] which is 'zero' $newList[3] receives $list[1] which is 'one' $newList[4] receives $list[2] which is 'two' $newList[0] receives $list[3] which is 'three' $newList[2] receives $list[4] which is 'four' whereas this code @newList = @list[@newOrder]; Means:- $newList[0] receives $list[1] which is 'one' $newList[1] receives $list[3] which is 'three' $newList[2] receives $list[4] which is 'four' $newList[3] receives $list[0] which is 'zero' $newList[4] receives $list[2] which is 'two'

      An important distinction, and a hard one for me to spot given my data. Thanks for this.

        You're welcome, glad to be of use. It could have been worse, the data could have been all 1s :)
Re: Reordering Arrays?
by davorg (Chancellor) on Jul 28, 2006 at 14:23 UTC

    Array slices are your friend.

    @new_array[@new_index_order] = @orig_array;
    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Reordering Arrays?
by BrowserUk (Patriarch) on Jul 28, 2006 at 14:24 UTC

    Like this?

    my @orig_array = qw(0 1 1 0 1 0 0 0 1 1 1 0 0 0 0); my @new_index_order = qw(8 3 4 9 11 6 7 0 14 10 1 12 2 5 13);; my @new_array = @orig_array[ @new_index_order ];; print @new_array;; 1 0 1 1 0 0 0 0 0 1 1 0 1 0 0

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Reordering Arrays?
by GrandFather (Saint) on Jul 29, 2006 at 04:47 UTC

    an interesting alternative for those to whom slices are less natural is:

    map {$list[$_]} @newOrder;

    What is more interesting is that the time for each version is essentially the same:

    Rate toOrder mapOrder fromOrder toOrder 4292/s -- -1% -1% mapOrder 4334/s 1% -- -1% fromOrder 4357/s 1% 1% --

    DWIM is Perl's answer to Gödel
      an interesting alternative for those to whom slices are less natural
      Though it's nice of Perl to offer alternative ways to achieve the same thing, that are even almost as concise, but that's still no excuse not to learn about array slices. After all, they're an essential part of what makes coding in Perl so elegant.

        Oh, I fully agree. I was more interested in the benchmark result. I really expected map to be much more expensive than slicing so I was rather surprised by the result. The result holds good for arrays of at least 100_000 elements.


        DWIM is Perl's answer to Gödel