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

Hi Monks

I'm trying to figure out how to print unique months in their proper order. I have a Hash of Hashes and I'm storing the unique values into an array, but that may not be the best way to do it in order to achieve my goal, which is to display all the unique months in proper order from my available data...jan,feb,mar, etc.

I'm hoping someone can help with this and maybe even show a better(using less lines of code) way to accomplish this task. My code is as follows.

#!/usr/bin/perl use strict; my %HoH; my $months; my $key; my %seen; my @uniq; my $client; my $Months_count; while (<DATA>) { ($client,$Months_count) = split /\|/, $_; my %by_month = split ' ', $Months_count; $HoH{$client} = \%by_month; } while ( ($client, $months) = each %HoH ) { while (defined ($key = each %$months)) { $seen{$key}++; } @uniq = keys %seen; } print "@uniq\n"; __DATA__ IBM | February 1 March 5 July 4 Oracle| January 3 March 4 April 6 May 5 RedHat | March 2 June 3 August 1

Any help is greatly appreciated!

Replies are listed 'Best First'.
Re: How to print months in proper order from array
by stevieb (Canon) on Aug 30, 2016 at 20:07 UTC

    Are you trying to sort unique per client?

    use warnings; use strict; use Data::Dumper; my %clients; while (<DATA>) { my ($client, $rest) = split /\|/; $rest =~ s/\s+//g; my @months = split /\d+/, $rest; $clients{$client} = \@months; } print Dumper \%clients; __DATA__ IBM | February 1 March 5 July 4 Oracle| January 3 March 4 April 6 May 5 RedHat | March 2 June 3 August 1

    Output:

    $VAR1 = { 'IBM ' => [ 'February', 'March', 'July' ], 'Oracle' => [ 'January', 'March', 'April', 'May' ], 'RedHat ' => [ 'March', 'June', 'August' ] };

      I'm not trying to sort unique by client, but unique from all clients. So if IBM had order in January, and Oracle had order in March, the unique months would be Jan and Mar.

      Thanks

        Here's a way without external modules that I think does what you want. It does so by setting up a month to month num hash, and then after collecting all of the month names, get the unique ones, then sort them based on their month number in the $month_names hash:

        use warnings; use strict; use Data::Dumper; my %month_names = ( January => 1, February => 2, March => 3, April => 4, May => 5, June => 6, July => 7, August => 8, September => 9, October => 10, November => 11, December => 12, ); my @months; while (<DATA>) { my ($client, $rest) = split /\|/; $rest =~ s/\s+//g; push @months, split /\d+/, $rest; } @months = uniq(@months); @months = sort { $month_names{$a} <=> $month_names{$b} } @months; print Dumper \@months; sub uniq { my %seen; grep ! $seen{$_}++, @_; } __DATA__ IBM | February 1 March 5 July 4 Oracle| January 3 March 4 April 6 May 5 RedHat | March 2 June 3 August 1

        Output:

        $VAR1 = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August' ];

        Another way, avoiding any sorting:

        use strict; use warnings; use 5.010; my @month_names = ( qw / January February March April May June July August September October November December / ); my %month_hash; while ( my $line = <DATA> ) { $month_hash{$_} = 1 for split /[^a-z]+/i, $line; } for ( @month_names ) { say if $month_hash{$_}; } __DATA__ IBM | February 1 March 5 July 4 Oracle| January 3 March 4 April 6 May 5 RedHat | March 2 June 3 August 1