Stable sort using a field

I have a formatted text file containing records separated by a | [pipe]. I need to sort this file using the third field, but also need to ensure that it is a stable sort. How can I do this?
smart_sagittarianAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Kim RyanIT ConsultantCommented:
what do you mean by stable? One apporach would br
FOr all lines
1. extract the third field from each line
2. update a hash, with key as third filed, and value as line number
3. sort the file by the new order defined in your hash

or in unix something like
sort -t '|' +2 infile outfile
smart_sagittarianAuthor Commented:
What you have suggested is a lengthy way of doing it.

Stable sort prevents further sorting of records with the same matching field value. To illustrate with an example, say the input file looks something like

b 234 asdsf
z 123 fsdfg
a 234 dfgdfg

Normally, sorting based on the second [numeric] field would yield the result

z 123 fsdfg
a 234 dfgdfg
b 234 asdsf

Here, the rows containing 234 have been further sorted, which I dont want. To prevent this there is a 'stable' option in sort. I googled and noticed that perl supports this, but could make no sense out of what was written.
Kim RyanIT ConsultantCommented:
Ok, understand what you mean by stable sort now.The  results are sorted by the third column and where duplicates occur, ordering is then by occurence within the file (no secondary sort). The unix sort utility will do this

Here http://search.cpan.org/~cnandor/File-Sort-1.01/Sort.pm is a perl module with same functionality as Unix sort
Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

ozoCommented:
use sort 'stable';
smart_sagittarianAuthor Commented:
Can I actually have a piece of code which does this? I came across the following lines from the net but dont understand how it works. I know this is what I am looking for but dont know how to change it to suit my requirements.

@out = sort {

            (split ":", $a, 2)[0] cmp (split ":", $b, 2)[0]
   } @input
mjcoyneCommented:
Try it this way:

#!/usr/bin/perl -w
use strict;

my @data = <DATA>;
my @sorted = map { $_->[0] } sort fieldsort map { [$_, split] } @data;
print @sorted;

sub fieldsort {
$a->[2] <=> $b->[2]; }

__DATA__
b 234 asdsf
z 123 fsdfg
a 234 dfgdfg
k 012 gnrewa
h 842 glovfdsa
j 012 gnrewa
geotigerCommented:

Here is to sort on the 3rd field delimited by pipe:

@out = sort {
            (split "I", $a, 3)[2] cmp (split "|", $b,3)[2]
   } @input
geotigerCommented:

my @input = <DATA>;

my @out = sort {
         chomp;
         (split /\|/, $a, 3)[2] cmp (split /\|/, $b,3)[2]
   } @input;

print @out;


__DATA__
1|b|234|asdsf
2|z|123|fsdfg
3|a|234|dfgdfg
4|k|012|gnrewa
5|h|842|glovfdsa
6|j|012|gnrewa


The output :

4|k|012|gnrewa
6|j|012|gnrewa
2|z|123|fsdfg
1|b|234|asdsf
3|a|234|dfgdfg
5|h|842|glovfdsa
mjcoyneCommented:
Opps -- sorry, I got hung up on your example data for a stable sort.  I forgot about the pipe delimiter, and the third field.  An easy fix to my prior answer:

#!/usr/bin/perl -w
use strict;

my @data = <DATA>;
my @sorted = map { $_->[0] } sort fieldsort map { [$_, split /\|/] } @data;
print @sorted;

sub fieldsort {
$a->[3] <=> $b->[3]; }

__DATA__
1|b|234|asdsf
2|z|123|fsdfg
3|a|234|dfgdfg
4|k|012|gnrewa
5|h|842|glovfdsa
6|j|012|gnrewa


If you'd rather not slurp the file, you can do it this way:

#!/usr/bin/perl -w
use strict;
my (@sorted, @data);

while (<DATA>) {
    push (@data, $_);
    @sorted = map { $_->[0] } sort fieldsort map { [$_, split/\|/] } @data;
}

print @sorted;

sub fieldsort {
$a->[3] <=> $b->[3];
}

__DATA__
1|b|234|asdsf
2|z|123|fsdfg
3|a|234|dfgdfg
4|k|012|gnrewa
5|h|842|glovfdsa
6|j|012|gnrewa

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ozoCommented:
#on 5.8.0 or later
use v5.8;
use sort 'stable';
print map{$_->[1]} sort{$a->[0] cmp $b->[0]} map{[(split/\|/)[2],$_]}<DATA>;

__DATA__
1|b|234|asdsf
2|z|123|fsdfg
3|a|234|dfgdfg
4|k|012|gnrewa
5|h|842|glovfdsa
6|j|012|gnrewa
smart_sagittarianAuthor Commented:
Thanks for all your answers. I got what I wanted.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.