У меня есть массив на Perl:
my @my_array = ("one","two","three","two","three");
Как удалить дубликаты из массива?
Вы можете сделать что-то подобное, как показано в perlfaq4:
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @array = qw(one two three two three);
my @filtered = uniq(@array);
print "@filtered\n";
Выходы:
one two three
Если вы хотите использовать модуль, попробуйте функцию uniq
из List::MoreUtils
В этом контексте это лексика my
, так что все в порядке. При этом, возможно, можно было бы выбрать более описательное имя переменной.
@ephemient: да, но если бы вы добавили сортировку в эту функцию, она бы превзошла $::a
и $::b
, не так ли?
@szabgab, если это так, это невероятно плохое дизайнерское решение для sort
использовать нелокальные переменные.
@BrianVandenberg Добро пожаловать в мир 1987 года - когда он был создан - и почти стопроцентная обратная совместимость для perl - так что от него невозможно избавиться.
sub uniq { my %seen; grep !$seen{$_}++, @_ }
- лучшая реализация, так как она поддерживает порядок без каких-либо затрат. Или, что еще лучше, воспользуйтесь одним из List :: MoreUtils.
@ vol7tron означает "обратная совместимость", извините, это меня беспокоило ;-)
Perl v5.26.0 и более поздние версии, List::Util
имеет uniq
, поэтому MoreUtils не потребуется
Мой обычный способ сделать это:
my %unique = ();
foreach my $item (@myarray)
{
$unique{$item} ++;
}
my @myuniquearray = keys %unique;
Если вы используете хеш и добавляете элементы в хеш. Вы также получаете бонус в виде знания того, сколько раз каждый элемент появляется в списке.
У этого есть обратная сторона - не сохранять исходный порядок, если он вам нужен.
Лучше использовать ломтики вместо цикла foreach
: @unique{@myarray}=()
Документация Perl поставляется с хорошей коллекцией часто задаваемых вопросов. Ваш вопрос часто задают:
% perldoc -q duplicate
Ответ, скопированный и вставленный из вывода приведенной выше команды, появится ниже:
Found in /usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod How can I remove duplicate elements from a list or array? (contributed by brian d foy) Use a hash. When you think the words "unique" or "duplicated", think "hash keys". If you don't care about the order of the elements, you could just create the hash then extract the keys. It's not important how you create that hash: just that you use "keys" to get the unique elements. my %hash = map { $_, 1 } @array; # or a hash slice: @hash{ @array } = (); # or a foreach: $hash{$_} = 1 foreach ( @array ); my @unique = keys %hash; If you want to use a module, try the "uniq" function from "List::MoreUtils". In list context it returns the unique elements, preserving their order in the list. In scalar context, it returns the number of unique elements. use List::MoreUtils qw(uniq); my @unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 1,2,3,4,5,6,7 my $unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 7 You can also go through each element and skip the ones you've seen before. Use a hash to keep track. The first time the loop sees an element, that element has no key in %Seen. The "next" statement creates the key and immediately uses its value, which is "undef", so the loop continues to the "push" and increments the value for that key. The next time the loop sees that same element, its key exists in the hash and the value for that key is true (since it's not 0 or "undef"), so the next skips that iteration and the loop goes to the next element. my @unique = (); my %seen = (); foreach my $elem ( @array ) { next if $seen{ $elem }++; push @unique, $elem; } You can write this more briefly using a grep, which does the same thing. my %seen = (); my @unique = grep { ! $seen{ $_ }++ } @array;
Джон iz в mah anzers крадет mah rep!
Я думаю, вы должны получить бонусные баллы за то, что действительно искали вопрос.
Мне нравится, что лучший ответ - 95% copy-paste и 3 предложения OC. Чтобы быть совершенно ясным, это является лучший ответ; Я просто нахожу этот факт забавным.
Установить List :: MoreUtils из CPAN
Затем в вашем коде:
use strict;
use warnings;
use List::MoreUtils qw(uniq);
my @dup_list = qw(1 1 1 2 3 4 4);
my @uniq_list = uniq(@dup_list);
Тот факт, что List :: MoreUtils не связан с perl, как бы повреждает переносимость проектов, использующих его :( (я, например, не буду)
@Ranguard: @dup_list
должен быть внутри вызова uniq
, а не @dups
@yassinphilip CPAN - одна из тех вещей, которые делают Perl настолько мощным и замечательным, насколько это возможно. Если вы пишете свои проекты, основанные только на основных модулях, вы накладываете огромное ограничение на свой код вместе с, возможно, полностью написанным кодом, который пытается делать то, что некоторые модули делают намного лучше, просто чтобы избежать их использования. Кроме того, использование основных модулей ничего не гарантирует, поскольку разные версии Perl могут добавлять или удалять основные модули из дистрибутива, поэтому переносимость все еще зависит от этого.
Perl v5.26.0 и более поздние версии, List::Util
имеет uniq
, поэтому MoreUtils не потребуется
Последний был довольно хорош. Я бы немного подправил:
my @arr;
my @uniqarr;
foreach my $var ( @arr ){
if ( ! grep( /$var/, @uniqarr ) ){
push( @uniqarr, $var );
}
}
Я думаю, что это, наверное, самый читаемый способ сделать это.
Переменная @array - это список с повторяющимися элементами
%seen=();
@unique = grep { ! $seen{$_} ++ } @array;
Можно сделать с помощью простого Perl one liner.
my @in=qw(1 3 4 6 2 4 3 2 6 3 2 3 4 4 3 2 5 5 32 3); #Sample data
my @out=keys %{{ map{$_=>1}@in}}; # Perform PFM
print join ' ', sort{$a<=>$b} @out;# Print data back out sorted and in order.
Блок PFM делает это:
Данные в @in передаются в MAP. MAP строит анонимный хеш. Ключи извлекаются из хеша и передаются в @out
Попробуйте это, похоже, для правильной работы функции uniq нужен отсортированный список.
use strict;
# Helper function to remove duplicates in a list.
sub uniq {
my %seen;
grep !$seen{$_}++, @_;
}
my @teststrings = ("one", "two", "three", "one");
my @filtered = uniq @teststrings;
print "uniq: @filtered\n";
my @sorted = sort @teststrings;
print "sort: @sorted\n";
my @sortedfiltered = uniq sort @teststrings;
print "uniq sort : @sortedfiltered\n";
Использование концепции уникальных хеш-ключей:
my @array = ("a","b","c","b","a","d","c","a","d");
my %hash = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";
Выход: а в б г
Логика: хэш может иметь только уникальные ключи, поэтому перебирайте массив, присваивайте любое значение каждому элементу массива, сохраняя элемент как ключ этого хеша. Верните ключи хэша, это ваш уникальный массив.
my @unique = keys {map {$_ => 1} @array};
Лучше создать подпрограмму, если предполагается, что мы будем использовать эту функцию в нашем коде несколько раз.
sub get_unique {
my %seen;
grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);
List::MoreUtils
use List::MoreUtils qw(uniq);
my @unique = uniq(@array);
Предыдущие ответы в значительной степени обобщают возможные способы решения этой задачи.
Тем не менее, я предлагаю модификацию для тех, кто не заботится о подсчет дубликатах, а делать заботится о порядке.
my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;
Обратите внимание, что ранее предложенный grep !$seen{$_}++ ...
увеличивает $seen{$_}
перед отрицанием, поэтому приращение происходит независимо от того, был ли он уже %seen
или нет. Вышеупомянутое, однако, короткое замыкание, когда $record{$_}
истинно, оставляя то, что когда-то было слышно «вне %record
».
Вы также можете пойти на эту нелепость, которая использует автоживификацию и наличие хеш-ключей:
...
grep !(exists $record{$_} || undef $record{$_}), @record;
Однако это может привести к некоторой путанице.
И если вас не интересует ни порядок, ни количество дубликатов, вы можете сделать еще один взлом, используя хеш-срезы и трюк, который я только что упомянул:
...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped
Для сравнения: sub uniq{ my %seen; undef @seen{@_}; keys %seen; }
Neat.
пожалуйста, не используйте $ a или $ b в примерах, так как они являются волшебными глобальными переменными sort ()