LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-18-2008, 10:39 AM   #1
RavenLX
Member
 
Registered: Oct 2004
Posts: 98

Rep: Reputation: 15
Question How do I do filtering in Perl (keep sort order and sort again by another means)?


Ok, I have a list of items and associated values that were pre-sorted according to value. Some values are the same so I want to sort those by name as well. Here's what I mean:

Desired Output:

Code:
pink|3.3
salmon|3.3
brown|3.0
orange|3.0
peach|3.0
red|3.0
tan|3.0
mustard|2.5
yellow|2.2
gold|1.8
green|1.8
hunter|1.8
lime|1.8
aqua|1.5
blue|1.5
cornflower|1.5
cyan|1.5
indigo|1.5
ivory|1.5
lavender|1.5
magenta|1.5
periwinkle|1.5
purple|1.5
sky|1.5
teal|1.5
violet|1.5
white|1.5
ecru|1.3
charcoal|1.1
eggshell|1.1
gray|1.1
black|1.0
Note that values that are the same are also sorted alphabetically. Now, here's my code, and the actual output:

Code:
#!/usr/bin/perl
use strict;
use Data::Dumper;

my @arr_data = (
				"pink|3.3",
				"salmon|3.3",
				"red|3.0",
				"orange|3.0",
				"peach|3.0",
				"tan|3.0",
				"brown|3.0",
				"mustard|2.5",
				"yellow|2.2",
				"gold|1.8",
				"lime|1.8",
				"green|1.8",
				"hunter|1.8",
				"blue|1.5",
				"sky|1.5",
				"periwinkle|1.5",
				"aqua|1.5",
				"cyan|1.5",
				"teal|1.5",
				"indigo|1.5",
				"violet|1.5",
				"lavender|1.5",
				"purple|1.5",
				"magenta|1.5",
				"cornflower|1.5",
				"white|1.5",
				"ivory|1.5",
				"ecru|1.3",
				"eggshell|1.1",
				"gray|1.1",
				"charcoal|1.1",
				"black|1.0"
				);

my (@temp, @index, @sorter, @sorted);
my ($item, $i);
foreach $item (@arr_data) {
	@temp = split("[\|]", $item);

	# Find index of others with same value
	@index = grep { $arr_data[$_] =~ /$temp[1]/ } 0..$#arr_data;

	# get the data
	undef @sorter;
	foreach $i (@index) {

		# add to sorter array
		$sorter[$#sorter + 1] = $arr_data[$i];

		# remove from old array
		splice @arr_data, $i, 1; 

	}

	# sort alphabetically
	@sorter = sort(@sorter);

	# add to new array
	@sorted = (@sorted, @sorter); 
}

# *** DEBUG ***
print Dumper(@sorted);
# *** END DEBUG ***
Output:

Code:
$VAR1 = 'pink|3.3';
$VAR2 = 'red|3.0';
$VAR3 = 'gold|1.8';
$VAR4 = 'mustard|2.5';
$VAR5 = 'orange|3.0';
$VAR6 = 'tan|3.0';
$VAR7 = 'peach|3.0';
$VAR8 = 'yellow|2.2';
$VAR9 = 'hunter|1.8';
$VAR10 = 'lime|1.8';
$VAR11 = 'sky|1.5';
$VAR12 = undef;
$VAR13 = undef;
$VAR14 = undef;
$VAR15 = undef;
$VAR16 = 'aqua|1.5';
$VAR17 = 'blue|1.5';
$VAR18 = 'charcoal|1.1';
$VAR19 = 'cornflower|1.5';
$VAR20 = 'eggshell|1.1';
$VAR21 = 'ivory|1.5';
$VAR22 = 'purple|1.5';
$VAR23 = 'teal|1.5';
$VAR24 = 'violet|1.5';
$VAR25 = undef;
$VAR26 = 'black|1.0';
$VAR27 = 'ecru|1.3';
$VAR28 = 'indigo|1.5';
$VAR29 = 'magenta|1.5';
$VAR30 = 'periwinkle|1.5';
$VAR31 = 'gray|1.1';
I'm just not sure how to approach this. Any help would be appreciated. Thanks!
 
Old 12-18-2008, 10:48 AM   #2
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
can you not use sort?
it would much easier.
i.e. not perl.
 
Old 12-18-2008, 11:23 AM   #3
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
You can do this type of thing by writing a custom sort subroutine. Here is a quick stab. It works, but there are probably more efficient ways to do it:
Code:
#!/usr/bin/perl
use warnings;
use strict;

my @arr_data = (
        "pink|3.3",
        "salmon|3.3",
        "red|3.0",
        "orange|3.0",
        "peach|3.0",
        "tan|3.0",
        "brown|3.0",
        "mustard|2.5",
        "yellow|2.2",
        "gold|1.8",
        "lime|1.8",
        "green|1.8",
        "hunter|1.8",
        "blue|1.5",
        "sky|1.5",
        "periwinkle|1.5",
        "aqua|1.5",
        "cyan|1.5",
        "teal|1.5",
        "indigo|1.5",
        "violet|1.5",
        "lavender|1.5",
        "purple|1.5",
        "magenta|1.5",
        "cornflower|1.5",
        "white|1.5",
        "ivory|1.5",
        "ecru|1.3",
        "eggshell|1.1",
        "gray|1.1",
        "charcoal|1.1",
        "black|1.0"
);

my @sorted = sort my_way @arr_data;

sub my_way {
  my($name_a, $value_a) = split /\|/, $a;
  my($name_b, $value_b) = split /\|/, $b;

  $value_b <=> $value_a or $name_a cmp $name_b;
}

foreach my $line (@sorted) {
  print "\t$line\n";
}
The output is what you want. I'll leave printing it out for folks to do on their own (rather than take up space here).

Edit: If you want the original array itself sorted just do
Code:
@arry_data = sort my_way @arr_data;

Last edited by Telemachos; 12-18-2008 at 01:38 PM.
 
Old 12-18-2008, 05:30 PM   #4
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
A second way which is a lot more complicated to look at, but perhaps more efficient:
Code:
#!/usr/bin/perl
use warnings;
use strict;

my @arr_data = (
        "pink|3.3",
        "salmon|3.3",
        "red|3.0",
        "orange|3.0",
        "peach|3.0",
        "tan|3.0",
        "brown|3.0",
        "mustard|2.5",
        "yellow|2.2",
        "gold|1.8",
        "lime|1.8",
        "green|1.8",
        "hunter|1.8",
        "blue|1.5",
        "sky|1.5",
        "periwinkle|1.5",
        "aqua|1.5",
        "cyan|1.5",
        "teal|1.5",
        "indigo|1.5",
        "violet|1.5",
        "lavender|1.5",
        "purple|1.5",
        "magenta|1.5",
        "cornflower|1.5",
        "white|1.5",
        "ivory|1.5",
        "ecru|1.3",
        "eggshell|1.1",
        "gray|1.1",
        "charcoal|1.1",
        "black|1.0"
);

my @sorted =  map   { $_->[0] }
              sort  { $b->[2] <=> $a->[2] || $a->[1] cmp $b->[1] }
              map   { [ $_,  split /\|/ ] } @arr_data;
  
foreach my $line (@sorted) {
  print "\t$line\n";
}
This uses the Schwartzian transform.
 
Old 12-19-2008, 02:57 AM   #5
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
the true way of unix would be:

/bin/sort -t\| -k2,3n -k1,2 < list
 
Old 12-19-2008, 03:13 AM   #6
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,120

Rep: Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120Reputation: 4120
Whoa - a perl thread that bigearsbilly refuses to answer.
What's the world coming to ???.
 
Old 12-19-2008, 03:25 AM   #7
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
ho ho!

as a true perl (zeal|big)ot and officianado
even I would go for the path of least typing on this one.



unless of course maybe the individual is
unfortunate enough to be using perl on windows.
 
Old 12-19-2008, 03:57 AM   #8
Telemachos
Member
 
Registered: May 2007
Distribution: Debian
Posts: 754

Rep: Reputation: 60
Quote:
Originally Posted by bigearsbilly View Post
the true way of unix would be:

/bin/sort -t\| -k2,3n -k1,2 < list
Two things: first, the OP wanted the numeric sort to be reversed (this is easily fixed); second, how exactly do we know that this isn't part of a larger project that is in Perl for a good reason?

In any case, here is a fixed sort incantation:
Code:
sort -t\| -k2,3nr -k1,2 < unsorted
 
Old 12-19-2008, 04:03 AM   #9
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
1. doh!
sort -k2,3rn -k1,2

2. I don't. Just opining Still it is best to use the power at your fingertips if you can.
 
Old 12-19-2008, 10:12 AM   #10
RavenLX
Member
 
Registered: Oct 2004
Posts: 98

Original Poster
Rep: Reputation: 15
bigearsbilly - I can't use sort (ie. not perl) because this is to be a part of a larger perl script I'm writing in which it all should be self-contained since I'm sorting data that is already loaded into the variables. I was trying to right a sort function for including in the script I'm working on.

Telemachos - Your Schwartzian transform code example is what I'll go with. Thank you.
 
  


Reply

Tags
filter, filtering, perl, sort



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
selection sort compiles but does not sort the array as desired ganesha Programming 2 04-20-2008 07:44 AM
Suggestion: Let's sort them in a,b,c... order fuelinux LQ Suggestions & Feedback 8 01-20-2008 10:35 AM
Sort order in nautilus Patrick K Ubuntu 4 06-12-2007 08:53 PM
Is there a line limit with the sort utility? Trying to sort 130 million lines of text gruffy Linux - General 4 08-10-2006 08:40 PM
how to 'sort' by file extension then alphabetical order adamrosspayne Linux - Newbie 4 07-04-2006 10:53 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:41 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration