package Sort::LOH;
use strict;
use Carp;
use vars qw($VERSION);
$VERSION = '0.01';
######################################################################
+#####
# D O C U M E N T A T I O N
=head1 NAME
Sort::LOH - Sorter for List of Hashes
=head1 SYNOPSIS
use strict;
use Sort::LOH;
my @SAMPLE_DATA = (
{F1 => "1", F2 => "2", F3 => "3",
FLOAT => "2", ST => "123 Main Street"},
{F1 => "2", F2 => "3", F3 => "4",
FLOAT => "9", ST => "45 Main Street",},
{F1 => "3", F2 => "4", F3 => "4",
FLOAT => "045", ST => "2459 Main St"},
{F1 => "4", F2 => "5", F3 => "6",
FLOAT => "1.3", ST => "2580 Main Street"},
{F1 => "5", F2 => "6", F3 => "7",
FLOAT => "9", ST => "39 Main Street"},
{F1 => "6", F2 => "7", F3 => "8",
FLOAT => "8.8", ST => "1888 Main Street"}
);
my $sorter = Sort::LOH->new(\@LOH);
my @sorted = $sorter->sortMe(["F3", "ST"]);
Sorting in reverse order:
my @sorted = $sorter->sortMe(["-F3", "-ST"]);
Sorting numerically, as opposed to the default alphabetical:
my @sorted = $sorter->sortMe(["FLOAT n"]);
=head1 DESCRIPTION
Takes in a LOH (List of Hashes) and an array of keys to sort
by and returns a new, sorted LOH. This module closely relates
to Sort::Fields in terms of it's interface how it does things.
On of it's main differences is that it is OO, so one can create
a Sort::LOH object and perform multiple sorts on it.
=cut
=head1 PUBLIC METHODS
=cut
# D O C U M E N T A T I O N
######################################################################
+#####
######################################################################
+#####
# C O N S T R U C T O R
=head2 new(\@LOH_to_sort)
The class constructor. To create a Sort::LOH object, simply call:
my $sorter = Sort::LOH->new(\@LOH);
=cut
sub new
{
my $class = shift;
my $self = {};
bless $self, $class;
unless (ref($self->{LOH} = shift) eq 'ARRAY') {
croak 'LOH needs a reference to a List of Hashes';
}
$self->{SORT_BY} = undef;
return $self;
}
# C O N S T R U C T O R
######################################################################
+#####
######################################################################
+#####
# S T A T I C M E T H O D S
=head2 element_class()
The name of the class for use in calling methods. This is a trick to
simplify inheritance of static factory methods that I got from Perlmon
+ks:
http://www.perlmonks.org/index.pl?node_id=74924 Inheriting classes wou
+ld
create override element_class with the name of their class.
=cut
sub element_class
{
return "Sort::LOH";
}
=head2 static(@sort_by, \@LOH_to_sort)
A static method that allows caller to make the class do all the work
with one swell foop:
my @sorted = Sort::LOH->static(["F1", "F2"], \@SAMPLE_DATA);
as opposed to
my $sorter = Sort::LOH->new(\@LOH);
my @sorted = $sorter->sortMe(["F1", "F2"]);
If caller wants to do multiple sorts, one should use the constructor,
+and
create a Sort::LOH object, since then one only has to pass in the data
+ once:
my $sorter = Sort::LOH->new(\@LOH);
my @sorted = $sorter->sortMe(["F1", "F2"]);
my @revSort = $sorter->sortMe(["-F1", "-F2"]);
=cut
sub static
{
my $self = shift;
my @sortby = shift || croak 'USAGE: Sort::LOH->factory(@LIST, \@L
+OH)';
my @loh = shift || croak 'Sort::LOH::factory() needs 2 args';
my $sorter = $self->element_class()->new(@loh);
return $sorter->sortMe(@sortby);
}
# S T A T I C M E T H O D S
######################################################################
+#####
######################################################################
+#####
# C L A S S M E T H O D S
=head2 sortMe(@sort_by)
The workhorse of this class. Expects a list of the LOH keys to determi
+ne
the sort order for the returned LOH.
my @sorted = $sorter->sortMe(["F1", "F2"]);
It is possible to do a reverse sort for a particular key by placing a
+minus
sign at the front of it:
my @sorted = $sorter->sortMe(["-F1", "-F2"]);
If one wants to do a numeric sort, instead of a alphabetical sort, pla
+ce
" n" after the key in the list:
my @sorted = $sorter->sortMe(["F1 n", "F2 n"]);
=cut
sub sortMe
{
my $self = shift;
$self->{SORT_BY} = shift || croak 'LOH needs a list of fields to s
+ort by';
my (@sortcode, @sortedLOH);
for (@{$self->{SORT_BY}}) {
unless (/^-?\w+\s*n?$/) {
croak "improperly formatted sort column specifier '$_'";
}
# Logic from Sort::Fields
# Set a and b depending on '-' flag at the start of a key
my ($a, $b) = /^-/ ? qw(b a) : qw(a b);
# Is it a string or numeric sort?
my $op = /\s+n$/ ? '<=>' : 'cmp';
# Get the actual column name
my ($col) = /^-?(\w+)/;
# Make sure that the sort key being passed in exists.
if (exists($self->{LOH}[0]{$col})) {
push @sortcode, "\$${a}->{${col}} $op \$${b}->{${col}}";
}
}
# Croak if there were no valid sort keys specified.
unless ($sortcode[0]) {
croak "No valid key match to sort LOH.";
}
my $sortcode = join " or ", @sortcode;
$sortcode = "sort { $sortcode } \@{\$self->{LOH}};";
@sortedLOH = eval "$sortcode";
if ($@) {
croak "Sort Failure of LOH\n$@";
}
return @sortedLOH;
}
# C L A S S M E T H O D S
######################################################################
+#####
1;
__END__
=head1 BUGS
=over
=item *
When a LOH is passed in that has a key that isn't present in each
row in the list, and the class is sorted on that key, sort will print
out errors for comparing with undefined values. For instance:
my @the_data = (
{ID => "a", CITY => "f1 f"},
{ID => "b", CITY => "f2 a"},
{ID => "c"},
{ID => "f", CITY => "f6 e"}
);
my $lohSorter = Sort::LOH->new(\@the_data);
my @sorted = $lohSorter->sortMe(["CITY"]);
Making sure that each key has an empty string as a defined value will
solve this:
my @better_data = (
{ID => "a", CITY => "f1 f"},
{ID => "b", CITY => "f2 a"},
{ID => "c", CITY => ""},
{ID => "f", CITY => "f6 e"}
);
I haven't figured out a way to trap this error as of yet.
=back
=head1 SUPPORT
The author always welcomes your comments, critiques, suggestions or
requests.
=head1 AUTHOR
Christopher Baker
<ignatz@ignatzmouse.com>
http://www.ignatzmouse.com
=head1 COPYRIGHT
Copyright (c) 2002 Christopher Baker. All rights reserved.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the
LICENSE file included with this module.
=head1 SEE ALSO
Sort::File, Data::Table
=cut
In reply to Sort::LOH
by ignatz
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.