Perl — Как мне подсчитать и распечатать вхождения доменов в массиве адресов электронной почты?

#arrays #perl #count #unique

#массивы #perl #подсчет #уникальный

Вопрос:

Я борюсь с этим уже пару дней и, похоже, не могу в этом разобраться.

У меня есть массив адресов электронной почты, которые были созданы с помощью push(@emails,$email) цикла while.

Я пытаюсь создать список уникальных доменов с количеством вхождений каждого в массиве.

Упорядочено по количеству вхождений.

Итак, если массив @emails имеет:

john@yadoo.com ringo@geemail.net george@zoohoo.org paul@yadoo.com

Я могу печатать:

 yadoo.com 2
geemail.net 1
zoohoo.org 1
  

Я нашел этот пример на основе электронных писем в файле, но это выше моего понимания. Может ли кто-нибудь помочь мне в более подробном примере кода, который можно использовать с массивом адресов электронной почты?

 perl -e 'while(<>){chomp;/^[^@] @([^@] )$/;$h{$1}  ;}
foreach $k (sort { $h{$b} <=> $h{$a} } keys %h)  {print $h{$k}." ".$k."n";} infile
  

Я также пробовал: (больше на моем уровне непонимания)

 foreach my $domain (sort keys %$domains) {
  print "$domain"."=";
  print $domains->{$domain}."n";
};
  

И

 my %countdoms;
$countdoms{$_}   for @domains;
print "$_ $countdoms{$_}n" for keys %countdoms;
  

Лучшим результатом, который я получил из множества различных попыток, было общее количество (которое равнялось 1812 (точное количество) с цифрой 2 рядом с ним. Возможно, я близок?

Комментарии:

1. P.S. Сначала я разделил домены в последних двух приведенных выше примерах, например: $domain = split('@',$email); push(@domains,$domain); в цикле, но нужен полный пример, включающий разделение, если необходимо, чтобы не запутать меня еще больше…

Ответ №1:

Вместо того, чтобы давать вам другой ответ, позвольте мне объяснить вам, что делает ваш пример кода:

 while(<>){chomp;/^[^@] @([^@] )$/;$h{$1}  ;}
foreach $k (sort { $h{$b} <=> $h{$a} } keys %h)  {print $h{$k}." ".$k."n";} 
  

В первой строке подсчитываются домены из электронных писем в файлах.

while(<>) перебирает входные файлы построчно. Входные файлы — это файлы, переданные в качестве аргументов, или stdin, если аргументы не были переданы. Каждая строка помещается в $_ .

chomp; просто удаляет новую строку с конца $_ .

/^[^@] @([^@] )$/ это регулярное выражение, которое анализирует домен и применяется к $_ . Он проверяет что-то, у чего нет ‘@’ в первой части, затем ‘@’, а затем нет ‘@’ в последней части. Он запоминает последнюю часть, которая будет сохранена в $1 . ^ и $ обозначают начало и конец строки соответственно.

$h{$1} ; использует домен (в $1 ) для увеличения количества в хэше %h . Это работает, даже если его нет, потому что undef здесь ведет себя как 0.

Чтобы это работало для вашего списка, вы можете просто сделать

 foreach(@emails) {/^[^@] @([^@] )$/;$h{$1}  ;}
  

Вторая строка выводит домены из хэша %h .

sort { $h{$b} <=> $h{$a} } keys %h возвращает список доменов, отсортированных по убыванию вхождения, с помощью функции сравнения $h{$b} <=> $h{$a} для просмотра количества. Обратите внимание, что это b <=> a, а не a <=> b, это делает его убывающим.

Остальная часть строки 2 выводит результат.

Комментарии:

1. Спасибо. Это очень ценно для меня. Спасибо, что нашли время объяснить.

Ответ №2:

Если ваш адрес электронной почты заполнен в массиве, вы получите количество для каждого домена. Я уверен, что кто-то может создать что-то более красивое!

 my @emails = ('john@yadoo.com','ringo@geemail.net','george@zoohoo.org','paul@yadoo.com');

my %domainCount;

foreach(@emails){
    if ($_ =~ /@(w .*)/){
        $domainCount{$1}  ;
    }
}

for my $domain (sort { $domainCount{$b} <=> $domainCount{$a}} keys %domainCount ){
    print "$domain - $domainCount{$domain}n";
}
  

Комментарии:

1. он говорит: «Упорядочено по количеству вхождений»

2. Теперь сортируем выходные данные в порядке убывания

3. ИДЕАЛЬНО! Как вы делаете это так быстро? Спасибо. Я буду изучать и узнаю, что здесь происходит.

Ответ №3:

Это немного грубо, потому что я устал от Perl, но это должно выполнить свою работу:

 use strict;
$|=1;
my ($dom, %hsh);
my @arr = ('john@yadoo.com', 'ringo@geemail.net', 'george@zoohoo.org', 'paul@yadoo.com');
foreach (@arr) {
    ($dom) = ($_ =~ /.*@(.*)$/);
    $hsh{$dom}  ;
}
foreach (keys %hsh) {
    print ("$_:$hsh{$_}n");
}
  

Комментарии:

1. Это сработало, но не по порядку, но большое вам спасибо. Помогает мне понять.

2. Просто добавьте ‘сортировать’ непосредственно перед ‘ключами’.

Ответ №4:

Другой вариант:

 use strict;
use warnings;

my @array 
    = qw<john@yadoo.com ringo@geemail.net george@zoohoo.org paul@yadoo.com>
    ;
my %dom_count;
$dom_count{ $_ }   foreach map { ( split '@' )[-1] } @array;
foreach my $pair ( 
    sort { $b->[1] <=> $a->[1] or $a->[0] cmp $b->[0] } 
    map  { [ $_ => $dom_count{ $_ } ] } keys %dom_count 
    ) { 
    print "@$pairn";
}
  

Комментарии:

1. ключи — это домены здесь, нет смысла их сортировать, я предполагаю, что вы хотели использовать сортировку с помощью <=>

2. Спасибо, это тоже работает, но не перечислено по порядку. Очень хорошо и использует map, который показывает мне, как это сделать! Какой полезный опыт! Спасибо!