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

Hi Monks
I have a file with the following data

2 2 2 3 3 3 4 4 4

However I want to present the data like this.

2 3 4 2 3 4 2 3 4

Thanks

j o h n i r l .

Sum day soon I'Il lern how 2 spelI (nad tYpe)

Replies are listed 'Best First'.
Re: Text Manipulation Quickie
by frankus (Priest) on Aug 15, 2002 at 10:41 UTC
    And for the file:
    2
    2
    2
    3
    3
    3
    4
    4
    5
    
    How would that be handled?
    this    or  that?
    2             2
    3             3
    4             2
    5             3
    2             4
    3             2
    4             3
    2             4
    3             5
    
    Fundamentaly whay you need is this:
    # Create an array of numbers with values... my %numbers = (); for (<FILE>){ chomp; $numbers{$_}++; # tally the occurences of numbers.. # Could add a preemptive 'last' if numbers not contiguous } while( %numbers ){ # satisfies "this" criteria, insert a reverse for "that" for ( sort keys %numbers ){ print "$_\n"; delete $numbers{$_} unless --$numbers{$_}; # Add a routine here to remove all higher values # and warn if numbers are non-contiguous. } }
    If this is homework, please note we're not here to do your thinking for you, just to help you think in Perl.

    --

    Brother Frankus.

    ¤

Re: Text Manipulation Quickie
by grummerX (Pilgrim) on Aug 15, 2002 at 10:46 UTC
    Try this:
    #!/usr/bin/perl -w use strict; my %value; for (<DATA>){ chomp; $value{$_}++ if $_; } my $max = (sort map { $value{$_} } keys %value)[-1]; for my $count (1..$max){ for (sort keys %value){ print "$_\n" if $value{$_} >= $count; } } __DATA__ 2 2 2 3 3 3 4 4 4
    Update:
    For an uneven list as those Frankus mentions, this will work according to his first example, ie:
    2
    2
    2
    3
    3
    3
    4
    4
    5
    
    Will return:

    2
    3
    4
    5
    2
    3
    4
    2
    3
    
    You can make it work like his second example by reversing the loop:
    for my $count (reverse 1..$max){

    Update (2): Got rid of pesky newlines per katgirl.

    -- grummerX

Re: Text Manipulation Quickie
by Abigail-II (Bishop) on Aug 15, 2002 at 11:54 UTC
    It's almost next to impossible to give a suitable program if the problem is only defined by a single example. But here's my shot. If gives the right output for your specific example, but if the data is different, the output might not be what you want. That happens if you give a single example, and no description. ;-)
    #!/usr/bin/perl use strict; use warnings 'all'; my (%data, @data, $data); while (<DATA>) { chomp; push @{$data {$_}} => $_; } @data = @data {sort {$a <=> $b} keys %data}; while (@data) { $data = shift @data; print pop @$data, "\n"; push @data => $data if @$data; } __DATA__ 2 2 2 3 3 3 4 4 4
    Abigail
      Sorry about the abruptness of the main question. I seemed to have forgotten my manners.
      What I am trying to do is sort results from a database into a predefined format. The results always come out sorted from the database and I want to rearrange them.
      And a little add on to that question
      What do I need to do if I have two (or more) columns seperated by semi-colons but I only want to sort by the first one?
      These maybe simple problems but this is my first attempt at using perl to manipulate text! And I have a looming deadline. So be gentle.
      2;3425; 2;4534; 2;2155; 3;1324; 3;1253; 3;3455; 4;3454; 4;3464; 4;3454;

      Required Result

      2;3425; 3;1324; 4;3454; 2;4534; 3;1253; 4;3464; 2;2155; 3;3455; 4;3454;

      Thanks for all your help and please excuse those of us brought up with no manners :-P

      j o h n i r l .

      Sum day soon I'Il lern how 2 spelI (nad tYpe)

        But you're still not defining the question in any manner that we can accurately extrapolate what you're trying to do. Especially when you use the word sort. We define sort to put all occurances of 2 before occurances of 3, before 4. So what you're asking us to do is unsort the data. There are an infinite number of ways of doing so, which result in arbitrary orderings (although the are only n! such orderings).

        Most of the solutions suggested simply counted the number of 2s, 3s and 4s (etc), and then repeatedly printed one of each (in ascending order) as long as necessary: they were actually discarding the original data.

        What it seems like you're after is

        foreach (<DATA>) { ($key, $val)=split ';', $_, 2; push @{$store{$key}}, $val; } while (keys %store) { foreach $key (sort keys %store) { print join ';', $key, shift @{$store{$key}}; delete $store{$key} unless scalar @{$store{$key}}; } } __DATA__ 2;3425; 2;4534; 2;2155; 3;1324; 3;1253; 3;3455; 4;3454; 4;3464; 4;3454;
        which is, essentially, just a variation of that theme.

        The answer to your 'little add' is to use split to extract the individual values

        --
        Tommy
        Too stupid to live.
        Too stubborn to die.

        my @sorted = do {no warnings 'numeric'; sort {$a <=> $b} @array};
        Abigail
Re: Text Manipulation Quickie
by demerphq (Chancellor) on Aug 15, 2002 at 13:01 UTC
    Heres yet another solution... As for the others the behaviour for when your file contains a different set of digits is only assumed to be correct. Basically it outputs inorder sequences of the input file until all of the numbers in the input file have been exhausted.

    my @array; while (<DATA>) { chomp; $array[$_]++; } my $found_flag=1; while ($found_flag) { $found_flag=0; for my $o (0..$#array) { if ($array[$o]) { print $o,"\n"; $array[$o]--; $found_flag=1; } } } __DATA__ 2 2 2 3 3 3 4 4 4

    Yves / DeMerphq
    ---
    Software Engineering is Programming when you can't. -- E. W. Dijkstra (RIP)