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

How do I alphabetize a list of email addresses by domain?

i was thinking of something like:
@emails
%prefixes -- key:username value:index
%suffixes -- key: domain.com value:index

sort suffixes, merge with prefixes into new
@sortedEmails

this seems ridiculously complicated and messy to me

help!
  • Comment on How do I alphabetize a list of email addresses by domain?

Replies are listed 'Best First'.
Re: How do I alphabetize a list of email addresses by domain?
by Chmrr (Vicar) on Apr 20, 2002 at 07:47 UTC

    Wield the Schwartzian Transform for the powers of good:

    @sortedEmails = map {$_->[0]} sort {$a->[2] cmp $b->[2]} map {[$_, split /@/]} @emails;

    perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'

      That only sorts @emails by domains. To further sort the addresses within each domain, you'd need something like ...

      sort { $a->[2] cmp $b->[2] # by domain first, || $a->[1] cmp $b->[1] # then username }

      Update: Oops, missed the ||. Thanks Chmrr.

          --k.


        That only sorts @emails by domains.

        Quite admittedly. But to quote the original poster:

        How do I alphabetize a list of email addresses by domain?

        ..but I can quite see your point. Anyways, you'll want to plonk an "or" between your two lines of code so that it compiles. :)

        Depending on how much the anonymous monk cares, they may or may not want to go whole hog and use Zaxo's more precise and tolerant answer.

        perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'

Re: How do I alphabetize a list of email addresses by domain?
by Zaxo (Archbishop) on Apr 20, 2002 at 09:02 UTC

    Without trying to optimize anything, here's an approach using Mail::Address:

    # @emails exists already use Mail::Address; my @sorted_by_domain_then_user = map { $_-> format } sort { $a->host cmp $b->host or $a->user cmp $b->user } map {Mail::Address->parse($_)} @emails;
    This may not be exactly what you want, but should be close.

    After Compline,
    Zaxo

Re: How do I alphabetize a list of email addresses by domain?
by particle (Vicar) on Apr 20, 2002 at 13:24 UTC
    my @emails = qw/bob@a.com adam@c.com bob@c.com ralph@b.a.com/; { local $,="\n"; print @emails, $n; print map { scalar reverse } sort( map { scalar reverse } @emails +), $/; }
    prints:
    bob@a.com adam@c.com bob@c.com ralph@b.a.com ralph@b.a.com bob@a.com bob@c.com adam@c.com
    $, and $/ are merely for printing. you'd probably want something like
    @sorted_emails = map { scalar reverse } sort( map { scalar reverse } @ +emails );

    ~Particle ;Þ

      This will break down when you encounter domain names not ending in ".com".

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: How do I alphabetize a list of email addresses by domain?
by Anonymous Monk on Apr 20, 2002 at 22:45 UTC
    thank you all..

    i did some testing.. and my first idea seems to be the fastest (though i haven't tried the newer posts yet). i've created dummy lists of 100,1000,...1,000,000 emails, and this seems to take half as much time as the first reply
    $i = 0; for (@emails){ @email = split /@/, $_; push @{ $domains{$email[1]} }, $i; $prefixes[$i] = $email[0]; $i++; } foreach $key (sort keys %domains) { foreach ( @{ $domains{$key} } ) { push @sortedEmails, ( $prefixes[$_] . "@" . $key ); } }
Re: How do I alphabetize a list of email addresses by domain?
by lemming (Priest) on Apr 21, 2002 at 01:35 UTC

    Another thing to watch out for: username@machinename.domainname.ext

Re: How do I alphabetize a list of email addresses by domain?
by Anonymous Monk on Apr 21, 2002 at 19:37 UTC
    well, i need to do this to feed a mailinglist into Mail::Bulkmail -- which can send emails within 1 envelope to each machine... so the machinename.domainname.tld works in this case anyways, i noticed a way to make it even slightly faster (about 8%)...
    %domains = {}; for (@emails){ @email = split /@/, $_; if (!$domains{$email[1]}){ $domains{$email[1]} = []; } push @{ $domains{$email[1]} }, $email[0]; } foreach $domain (sort keys %domains) { foreach $recipient ( @{ $domains{$domain} } ) { push @sorted, ( $recipient . "@" . $domain ); } }