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

I've got two strings of numbers, both containing a certain number of digits. Just for simplicity, lets assume that both variables contain four numbers. One variable has digits 1 through 4 in a specified order. The other variable has any digits 0 through 9. What is the best way to arrange the numbers in the second variable in accordance to the first variable? I'm sure that made no sense, so I'll try to make a visual representation using pretty tables :)

$digits = 4; $order = 4213; $rearrangeme = 9876;

4213
9876
Would Lead To..
17
28
36
49

7869 would be the final result.

After trying to acheive this with an elaborate series of split, s///, and substr, I spent about 2 hours trying to debug it, but to no avail. I'm sure theres probably some really simple way of doing this using a hash or something that I am just overlooking.

Thanks a lot for any help you could offer.

Replies are listed 'Best First'.
Re: Rearranging Numbers
by quidity (Pilgrim) on Nov 23, 2000 at 08:53 UTC

    This is quite simple:

    $order = 4213; $before = 9876; @ordered[split(//, $order)] = split(//, $before); $after = join '', @ordered;

    This turns both strings of digits into lists of single digits, then uses the list defining the order to fill an array slice with the number in need of ordering. When this is printed, you get them out in the right order, the first element of @ordered is empty though, but in this case that doesn't matter too much. Remember also that this will break with more than nine digits, or ten if you allow for '0' to be used when ordering (it comes before 1).

      So (w/ a little help from my friends ;-):
      @order = qw(4 2 1 3 0 5); @before = qw(9 8 7 6 5 11); @ordered[@order] = @before; $after = join ', ', @ordered; print join ", ", @order, " order\n"; print join ", ", @before, " before\n"; print "$after\n";
      gives you the above w/ real numbers, er, integers, not just the string/chars. FWIW
      (waiting for dinner roles to bake)

      a

Re: Rearranging Numbers
by Dominus (Parson) on Nov 23, 2000 at 21:16 UTC
    This is a special case of The Indirect Sort.

    In the Indirect Sort, you have two arrays of items, and you want to sort the second array into the order that is defined by the first array.

    (To get the two arrays, use split // on the two numbers.)

    So the indirect sort method says to use this:

    @order = split //, $order; @rearrangeme = split //, $rearrangeme; @indices = sort { $order[$a] <=> $order[$b] } (0..$digits-1); @answer = @rearrangeme[@indices];
    quidity's solution above is simpler, but the Indirect Sort technique is like a recipe that you can apply without thinking whenever you have to arrange one array items into the order that is specified by a different array, so it's worth remembering.

Re: Rearranging Numbers
by fundflow (Chaplain) on Nov 23, 2000 at 11:00 UTC
Re: Rearranging Numbers
by galande (Initiate) on Nov 23, 2000 at 14:12 UTC
    Hi,

    You just have to use hash with split and it will take you to target.
    You can try this ...
    #! /usr/bin/perl -w $digits = 4; $order = 4213; $arrange= 9876; $i = 0; while($i < $digits){ $hash{(split(//,$order))[$i]} = (split(//,$arrange))[$i]; $i++; } foreach (sort(split(//,$order))){ printf("%d => %d\n",$_,$hash{$_}); }

    Have a fun .....