Perl'deki bir diziden yinelenen öğeleri nasıl kaldırabilirim?


156

Perl bir dizi var:

my @my_array = ("one","two","three","two","three");

Kopyaları diziden nasıl kaldırabilirim?

Yanıtlar:


168

Perlfaq4'te gösterildiği gibi böyle bir şey yapabilirsiniz :

sub uniq {
    my %seen;
    grep !$seen{$_}++, @_;
}

my @array = qw(one two three two three);
my @filtered = uniq(@array);

print "@filtered\n";

Çıktılar:

one two three

Bir modül kullanmak istiyorsanız uniq,List::MoreUtils


28
Lütfen $ a veya $ b örneklerini kullanmayın, çünkü bunlar sıralamadaki sihirli küresellerdir ()
szabgab

2
myBu kapsamda bir sözlük, bu yüzden iyi. Bununla birlikte, muhtemelen daha açıklayıcı bir değişken adı seçilebilir.
ephemient

2
@ ephemient evet, ama eğer bu fonksiyona sıralama ekleyecekseniz, koz olur $::ave $::bdeğil mi?
vol7ron

5
@BrianVandenberg 1987 dünyasına hoş geldiniz - bu yaratıldığı zaman - ve perl için neredeyse% 100 arka kelime karşılaştırması - bu yüzden ortadan kaldırılamaz.
szabgab

18
sub uniq { my %seen; grep !$seen{$_}++, @_ }siparişi ücretsiz olarak koruduğundan daha iyi bir uygulamadır. Ya da daha iyisi, List :: MoreUtils'ten birini kullanın.
ikegami

120

Perl dokümanları hoş bir SSS koleksiyonu ile birlikte gelir. Sorunuz sık soruluyor:

% perldoc -q duplicate

Yukarıdaki komutun çıktısından cevaplanan, kopyalanan ve yapıştırılan cevap aşağıda görünür:

/Usr/local/lib/perl5/5.10.0/pods/perlfaq4.pod içinde bulundu
 Bir listeden veya diziden yinelenen öğeleri nasıl kaldırabilirim?
   (brian d foy tarafından yazılmıştır)

   Bir karma kullanın. "Benzersiz" veya "çoğaltılmış" kelimelerini düşündüğünüzde,
   msgstr "hash tuşları".

   Elemanların sırasını umursamıyorsanız, sadece
   karma oluşturun ve sonra anahtarları çıkarın. Nasıl olduğun önemli değil
   bu karmayı yaratın: sadece benzersiz öğeleri almak için "anahtarları" kullanın.

       % karma = harita {$ _, 1} @array;
       # veya bir karma dilim: @hash {@array} = ();
       # veya bir foreach: $ hash {$ _} = 1 foreach (@array);

       @unique = anahtarlar% kare;

   Bir modül kullanmak istiyorsanız, "uniq" işlevini
   "Liste :: MoreUtils". Liste bağlamında benzersiz öğeleri döndürür,
   Listedeki sıralarını koruyarak. Skaler bağlamda,
   benzersiz elemanların sayısı.

       Listeyi kullan :: MoreUtils qw (uniq);

       benim benzersiz = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 1,2,3,4,5,6,7
       $ benzersiz = uniq (1, 2, 3, 4, 4, 5, 6, 5, 7); # 7

   Ayrıca her öğeyi gözden geçirebilir ve gördüklerinizi atlayabilirsiniz
   önce. Takip etmek için bir karma kullanın. Döngü ilk kez bir
   öğesinde, bu öğenin% Seen içinde anahtarı yok. "Next" ifadesi
   anahtar ve hemen "undef" değerini kullanır, böylece döngü
   "itmeye" devam eder ve o tuşun değerini artırır. Sonraki
   döngü aynı öğeyi gördüğünde, anahtarı karmada bulunur ve
   bu anahtarın değeri doğrudur (0 veya "undef" olmadığı için)
   sonraki bu yinelemeyi atlar ve döngü bir sonraki öğeye gider.

       benim benzersiz = ();
       % 'mim görüldü = ();

       (@array)
       {
         sonra $ {$ elem} ++ görürse;
         it @unique, $ elem;
       }

   Aynı şeyi bir grep kullanarak daha kısaca yazabilirsiniz.
   şey.

       % 'mim görüldü = ();
       @unique = grep {! $ görüldü {$ _} ++} @array;


17
Mah iz içinde John iz mah temsilcisi çalmak!
brian d foy

5
Soruyu gerçekten aramak için bonus puan almanız gerektiğini düşünüyorum.
Brad Gilbert

2
En iyi cevabın% 95 kopyala yapıştır ve 3 OC cümlesi olduğunu seviyorum. Gayet açık olmak gerekirse, bu ise en iyi cevabı; Sadece bu gerçeği eğlenceli buluyorum.
Parthian Shot

70

Yükleme Listesi :: MoreUtils CPAN

Sonra kodunuzda:

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);

4
List :: MoreUtils'in perl ile birlikte paketlenmemiş olması, onu kullanan projelerin taşınabilirliğine zarar verir :( (Biri için I)
yPhil

3
@ Koruma: çağrı @dup_listiçinde olmalı uniq, değil@dups
incutonez

@yassinphilip CPAN, Perl'i olabildiğince güçlü ve harika yapan şeylerden biridir. Projelerinizi yalnızca temel modüllere göre yazıyorsanız, bazı modüllerin sadece bunları kullanmaktan kaçınmak için daha iyisini yapmayı deneyen muhtemelen yazılı olarak yazılmış kodla birlikte büyük bir sınır koyarsınız. Ayrıca, çekirdek modülleri kullanmak hiçbir şeyi garanti etmez, çünkü farklı Perl versiyonları çekirdek modülleri dağıtımdan ekleyebilir veya dağıtımdan kaldırabilir, bu nedenle taşınabilirlik hala buna bağlıdır.
Francisco Zarabozo

24

Bunu yapmanın olağan yolu:

my %unique = ();
foreach my $item (@myarray)
{
    $unique{$item} ++;
}
my @myuniquearray = keys %unique;

Bir karma kullanır ve öğeleri karma öğesine eklerseniz. Ayrıca, her bir öğenin listede kaç kez göründüğünü bilme bonusu da vardır.


2
Bu, ihtiyacınız varsa, orijinal siparişi korumamanın dezavantajına sahiptir.
Nathan Fellman

Döngü yerine dilimleri kullanmak daha iyidir foreach:@unique{@myarray}=()
Onlyjob

8

@Array değişkeni yinelenen öğeler içeren listedir

%seen=();
@unique = grep { ! $seen{$_} ++ } @array;

7

Basit bir Perl tek astar ile yapılabilir.

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 bloğu bunu yapar:

@İn'deki veriler MAP'a beslenir. MAP anonim bir karma oluşturur. Anahtarlar karma'dan çıkarılır ve @out'a beslenir


4

Sonuncusu oldukça iyiydi. Sadece biraz değiştirirdim:

my @arr;
my @uniqarr;

foreach my $var ( @arr ){
  if ( ! grep( /$var/, @uniqarr ) ){
     push( @uniqarr, $var );
  }
}

Bunun muhtemelen en okunaklı yol olduğunu düşünüyorum.


4

Yöntem 1: Karma kullanma

Mantık: Bir karma yalnızca benzersiz anahtarlara sahip olabilir, bu nedenle dizi üzerinde yineleme yapın, öğeyi bu karma öğesinin anahtarı olarak tutarak dizinin her öğesine herhangi bir değer atayın. Karma anahtarları, benzersiz diziniz.

my @unique = keys {map {$_ => 1} @array};

Yöntem 2: Yeniden kullanılabilirlik için yöntem 1'in genişletilmesi

Bu işlevselliği kodumuzda birden çok kez kullanmamız gerekiyorsa altyordam yapmak daha iyidir.

sub get_unique {
    my %seen;
    grep !$seen{$_}++, @_;
}
my @unique = get_unique(@array);

Yöntem 3: modülü kullanın List::MoreUtils

use List::MoreUtils qw(uniq);
my @unique = uniq(@array);

1

Önceki cevaplar bu görevi yerine getirmenin olası yollarını hemen hemen özetliyor.

Ancak, ben olanlar için bir değişiklik önermek yok umurumda sayma çiftleri, ama yapmak amacıyla umurumda.

my @record = qw( yeah I mean uh right right uh yeah so well right I maybe );
my %record;
print grep !$record{$_} && ++$record{$_}, @record;

İhmal edilmeden önce daha önce önerilen grep !$seen{$_}++ ...artışların olduğuna dikkat edin $seen{$_}, bu nedenle artış daha önce olup olmadığına bakılmaksızın gerçekleşir %seen. Bununla birlikte, yukarıdakiler, $record{$_}doğru olduğunda kısa devreler , duyulanları bir kez 'kapalı' olarak bırakır %record.

Ayrıca, otomatik doğrulama ve karma anahtarlarının varlığından yararlanan bu saçmalık için de gidebilirsiniz:

...
grep !(exists $record{$_} || undef $record{$_}), @record;

Ancak bu biraz karışıklığa neden olabilir.

Ve ne sipariş ne de yinelenen sayımı önemsiyorsanız, karma dilimleri ve az önce bahsettiğim hileyi kullanarak başka bir kesmek için yapabilirsiniz:

...
undef @record{@record};
keys %record; # your record, now probably scrambled but at least deduped

Karşılaştırma yapanlar için: sub uniq{ my %seen; undef @seen{@_}; keys %seen; } Temiz.
stevesliva

0

Bunu deneyin, uniq işlevinin düzgün çalışması için sıralı bir listeye ihtiyacı var gibi görünüyor.

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";

0

Benzersiz karma anahtar kavramını kullanma:

my @array  = ("a","b","c","b","a","d","c","a","d");
my %hash   = map { $_ => 1 } @array;
my @unique = keys %hash;
print "@unique","\n";

Çıktı: acbd

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.