in reply to Help sorting contents of an essay

G'day harmattan_,

Welcome to the Monastery.

There are some issues with your code which aren't helping you.

There are some issues with your post which aren't helping us to help you.

You have two fundamental flaws in the code you have supplied.

In the code below, I've shown a single pass through the input which collects the data (@data_all) as well as other information (%data_info) that is used in various places by sort — there's no need to recalculate counts, or perform transformation for case-insensitive checks, multiple times.

Note: I used lc but fc would be a far better choice; fc requires Perl 5.16 or later — use fc if you have an appropriate Perl version.

You'll note a map-sort-map pattern in the code. That's called a Schwartzian Transform. Take a look at "A Fresh Look at Efficient Perl Sorting" for a description of that and other sorting methods.

I've include example code for each of the four sorts you mentioned. I believe the first three are what you want. The fourth may not be exactly what you're after: this is an example where expected output, as I wrote about above, would have really helped.

#!/usr/bin/env perl use strict; use warnings; use constant { NO_CASE => 0, COUNT => 1, }; my (@data_all, %data_info); while (<DATA>) { chomp; push @data_all, $_; if (exists $data_info{$_}) { ++$data_info{$_}[COUNT]; } else { $data_info{$_} = [lc, 1]; } } print "Sort alphabetically - ignore case\n"; print "$_\n" for map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, $data_info{$_}[NO_CASE] ] } @data_all; print "Sort alphabetically - capitalisation matters\n"; print "$_\n" for map { $_->[0] } sort { $a->[1] cmp $b->[1] || $a->[2] cmp $b->[2] || $a->[0] cmp $b->[0] } map { [ $_, substr($data_info{$_}[NO_CASE], 0, 1), substr($_, 0, 1) ] } @data_all; print "Sort by frequency - ignore alphabetical order\n"; print "$_->[1]: $_->[0]\n" for sort { $b->[1] <=> $a->[1] } map { [ $_, $data_info{$_}[COUNT] ] } keys %data_info; print "Sort by frequency - then by alphabetical order\n"; print "$_->[1]: $_->[0]\n" for sort { $b->[1] <=> $a->[1] || $a->[0] cmp $b->[0] } map { [ $_, $data_info{$_}[COUNT] ] } keys %data_info; __DATA__ bb Aa CC dD bb AA dD aa BB aa dD aA

Output:

Sort alphabetically - ignore case Aa AA aa aa aA bb bb BB CC dD dD dD Sort alphabetically - capitalisation matters AA Aa aA aa aa BB bb bb CC dD dD dD Sort by frequency - ignore alphabetical order 3: dD 2: aa 2: bb 1: Aa 1: BB 1: aA 1: CC 1: AA Sort by frequency - then by alphabetical order 3: dD 2: aa 2: bb 1: AA 1: Aa 1: BB 1: CC 1: aA

— Ken