seyrek sıralanmış diziler Interleaving

oy
7

Olayların listelerin bir dizi var. olaylar her zaman belirli bir sırayla gerçekleşmesi, ancak her olay hep böyle oluyor. İşte bir örnek girişi bulunuyor:

[[ do, re, fa, ti ],
 [ do, re, mi ],
 [ do, la, ti, za ],
 [ mi, fa ],
 [ re, so, za ]]

girdi değerleri herhangi doğasında düzeni yok. Onlar aslında sembolik yaratma ve arama yeniden dizin gibi mesaj. Bunlar bireysel listede sıralanır konum, ama ikinci ilk listesi ve 'mil' tek 'fa' bakmak ve diğer önce geldiği belirlemek için bir yolu yoktur.

O girdi almak ve sıralı bir liste oluşturmak için muktedir istiyorum bütün olaylar:

[ do, re, mi, fa, so, la, ti, za ]

ya da daha iyisi, bir sayım gibi her olay, hakkında bazı bilgiler:

[ [do, 3], [re, 3], [mi, 2],
  [fa, 2], [so, 1], [la, 1],
  [ti, 1], [za, 2] ]

Ben ne yapıyorum için bir isim var mı? algoritmalar var kabul edilir? eğer bu konularda ben Perl, bu yazıyorum, ama yalancı kod yapacağız.

Benim örnek girişini verilen biliyoruz, muhtemelen doğru düzenin garanti edilemez. Ama esas girişi vardır ton daha datapoints ve (bütün ihtiyacım gerçekten olan) bazı zeka ile doğru% 95 olacak emin hissediyorum. Sadece yapmak yoksa tekerleği yeniden icat etmek istemiyorum.

Oluştur 09/07/2010 saat 19:32
kaynak kullanıcı
Diğer dillerde...                            


10 cevaplar

oy
0
perl -de 0
  DB<1> @a = ( ['a','b','c'], ['c','f'], ['h'] ) 
  DB<2> map { @m{@{$_}} = @$_ } @a
  DB<3> p keys %m
chabf

Aklıma gelen Quickiest kısayol. Hangisi olursa olsun, en az bir kez şeyleri yinelemek zorunda ...

Cevap 09/07/2010 saat 19:42
kaynak kullanıcı

oy
0

Bu için mükemmel bir adaydır Birleştirme Sıralama . Algoritmanın oldukça iyi bir temsil için buraya wikipedia sayfasına gidin http://en.wikipedia.org/wiki/Merge_sort

Ne nitelendirdiler aslında birleştirme tür bir alt kümesi / küçük çimdik olduğunu. Bunun yerine bir sırasız dizilerde ile başlayan, size bir araya birleştirmek istediğiniz sıralanmış diziler bir dizi var. Eğer (sıralanacaktır) tek bir dizi var kadar Dizilerin çiftleri ve birleştirme fonksiyonu sonuçlarına wikipedia sayfasında açıklanan şekilde Sadece "birleştirme" işlevini çağırın.

istediğiniz şekilde çıkışını çimdik için, bir olay farklı bir olay daha, daha az eşit veya büyük olması durumunda dönebilirsiniz bir karşılaştırma işlevi tanımlamak gerekir. birleştirme işlevi eşittir iki olayı bulduğunda Ardından, tek bir etkinlik içine çökecek ve bu olay için bir sayım tutabilir.

Cevap 09/07/2010 saat 19:45
kaynak kullanıcı

oy
3

Teorik olarak konuşursak, bana şu algoritmayı önerdiğimiz:

  1. bir çizge oluşturun.
  2. bunlar zaten orada konum Her bir giriş için, [X, Y, Z], kenarları X> Y ve Y> Z oluşturun.
  3. Bir gerçekleştirme topolojik sıralama grafik.
  4. İşte bu kadar!

PS
Bu yalnızca tüm olaylar belirli bir sırada meydana geldiğini varsayarak olduğunu (her zaman!). Eğer durum değil, sorun NP-Complete olur.

PPS
Ve sadece yararlı bir şeyler var ki: Sıralama :: Topolojik (aslında çalışıp çalışmadığını bilmiyorum ama doğru görünüyor)

Cevap 09/07/2010 saat 19:48
kaynak kullanıcı

oy
0

Kabaca, adı Ben "karma" dır verecekti. Sen adı değer çiftleri içine şeyler koyuyoruz. Eğer siparişi bazı görünüş tutmak istiyorsanız, siparişi tutan bir dizi karma tamamlamak zorunda. Bu sıralama, benim için "karşılaşma sırası" dir.

use strict;
use warnings;

my $all 
    = [[ 'do', 're', 'fa', 'ti' ],
       [ 'do', 're', 'mi' ],
       [ 'do', 'la', 'ti', 'za' ],
       [ 'mi', 'fa' ],
       [ 're', 'so', 'za' ]
     ];

my ( @order, %counts );

foreach my $list ( @$all ) { 
    foreach my $item ( @$list ) { 
        my $ref = \$counts{$item}; # autovivs to an *assignable* scalar.
        push @order, $item unless $$ref;
        $$ref++;
    }
}

foreach my $key ( @order ) { 
    print "$key: $counts{$key}\n";
}

# do: 3
# re: 3
# fa: 2
# ti: 2
# mi: 2
# la: 1
# za: 2
# so: 1

Orada bunun gibi diğer cevaplar, ama benim bu düzgün autovivification hile içeriyor.

Cevap 09/07/2010 saat 20:31
kaynak kullanıcı

oy
2

Eğer çok koduna yazılı içine değil iseniz, Unix komut satırı yardımcı programını kullanabilirsiniz tsort:

$ tsort -
do re
re fa
fa ti
do re
re mi
do la
la ti
ti za
mi fa
re so
so za

Hangisi örnek girdi tüm çiftleri listesidir. Bu çıkış olarak üretir:

do
la
re
so
mi
fa
ti
za

hangi istediğini temelde.

Cevap 09/07/2010 saat 21:06
kaynak kullanıcı

oy
3

Sen kullanabilirsiniz tsort(a olarak bilinen makul-olmasa da eşsiz-sıralama düzeni anlaması için topolojik sırayla size gözlemledik sipariş itibaren). Sen okuma ilginizi çekebilir tsorts' orijinal kullanımını sorununuza yapısına çok benzer.

Not tsortbir asiklik grafik gerektirir. Senin örnekte açısından, bu tek sırayla yeniden izledi do görmek olamazdı diğerinde do ardından yeniden gelir.

#! /usr/bin/perl

use warnings;
use strict;

use IPC::Open2;

sub tsort {
  my($events) = @_;

  my $pid = open2 my $out, my $in, "tsort";

  foreach my $group (@$events) {
    foreach my $i (0 .. $#$group - 1) {
      print $in map "@$group[$i,$_]\n", $i+1 .. $#$group;
    }
  }

  close $in or warn "$0: close: $!";

  chomp(my @order = <$out>);
  my %order = map +(shift @order => $_), 0 .. $#order;
  wantarray ? %order : \%order;
}

Eğer seyrek olarak tanımlanan veri olduğundan, kod yukarıda sağlar tsortetkinlikler komşuluk matrisi hakkında mümkün olduğunca çok bilgi ile.

Bu bilgilere sahip bir histogram hesaplama ve bileşenlerini sıralama basittir:

my $events = [ ... ];

my %order = tsort $events;

my %seen;
do { ++$seen{$_} for @$_ } for @$events;

my @counts;
foreach my $event (sort { $order{$a} <=> $order{$b} } keys %seen) {
  push @counts => [ $event, $seen{$event} ];
  print "[ $counts[-1][0], $counts[-1][1] ]\n";
}

Sağladığınız sorunuzu girişi için, çıkışı

[Do, 3]
[La, 1]
[Re, 3]
[ số 1 ]
[Mi, 2]
[Fa, 2]
[Ti, 2]
[Za, 2]

Biz solfege sırasını biliyorum ama yeniden ve la kıyaslanamaz çünkü bu komik görünüyor kısmi sipariş ile tanımlanan $events: biz sadece onlar peşine yapmak gerekir de bunu biliyoruz.

Cevap 09/07/2010 saat 21:22
kaynak kullanıcı

oy
0

Sanırım bu da ne diyeceği gerçekten emin değilim, ancak bir giriş olarak diziler dizi verilen sırasını bulmak için bir yolunu. Esasen sözde kodu:

10 bütün dizilerde en erken öğeyi bulun
listesi üzerine o 20 itin
30 tüm dizilerden o öğeyi kaldırma
kalan herhangi öğeleri olup olmadığını 40 Goto 10

İşte çalışan bir prototip:

#!/usr/bin/perl

use strict;

sub InList {
    my ($x, @list) = @_;
    for (@list) {
        return 1 if $x eq $_;
    }
    return 0;
}

sub Earliest {
    my @lists = @_;
    my $earliest;
    for (@lists) {
        if (@$_) {
            if (!$earliest
                || ($_->[0] ne $earliest && InList($earliest, @$_))) {

                $earliest = $_->[0];
            }
        }
    }
    return $earliest;
}

sub Remove {
    my ($x, @lists) = @_;

    for (@lists) {
        my $n = 0;
        while ($n < @$_) {
            if ($_->[$n] eq $x) {
                splice(@$_,$n,1);
            }
            else {
                $n++
            }
        }
    }
}

my $list = [
    [ 'do', 're', 'fa', 'ti' ],
    [ 'do', 're', 'mi' ],
    [ 'do', 'la', 'ti', 'za' ],
    [ 'mi', 'fa' ],
    [ 're', 'so', 'za' ]
];

my @items;

while (my $earliest = Earliest(@$list)) {
    push @items, $earliest;
    Remove($earliest, @$list);
}

print join(',', @items);

Çıktı:

do, re, mi, fa, la, ti, bu nedenle, za

Cevap 09/07/2010 saat 21:42
kaynak kullanıcı

oy
0

Çözüm:

o asker tarafından değiştirildiği önce bu orijinal soruyu çözer.


#!/usr/local/bin/perl -w
use strict; 

   main();

   sub main{
      # Changed your 3-dimensional array to a 2-dimensional array
      my @old = (
                   [ 'do', 're', 'fa', 'ti' ],
                   [ 'do', 're', 'mi' ],
                   [ 'do', 'la', 'ti', 'za' ],
                   [ 'mi', 'fa' ],
                   [ 're', 'so', 'za' ]
                );
      my %new;

      foreach my $row (0.. $#old ){                           # loop through each record (row)
         foreach my $col (0..$#{$old[$row]} ){                # loop through each element (col)                    
            $new{ ${$old[$row]}[$col] }{count}++;
            push @{ $new{${$old[$row]}[$col]}{position} } , [$row,$col];
         }
      }

      foreach my $key (sort keys %new){
         print "$key : $new{$key} " , "\n";                   # notice each value is a hash that we use for properties 
      }      
   } 

Bilgi Al Nasıl:

   local $" = ', ';                       # pretty print ($") of array in quotes
   print $new{za}{count} , "\n";          # 2    - how many there were
   print "@{$new{za}{position}[1]} \n";   # 4,2  - position of the second occurrence
                                          #        remember it starts at 0   

Temelde biz karma elemanların benzersiz bir liste oluşturun. Bu elemanların her biri için bir sayıl içeren bir "özellik" karma var countve bir dizi position. Dizideki elementlerin sayısı elemanının birçok oluşumları orijinal ne kadar göre değişmelidir.

Hep bir skaler sürebilir beri sayıl özellik gerçekten gerekli değildir positionaynı numarayı almak için diziden. Not: Hiç / eklemek diziden öğeleri kaldırmak eğer countve positiononların anlamı korelasyon edilmeyecektir.

  • örnek: print scalar @{$new{za}{position}};Size aynı verecekprint $new{za}{count};
Cevap 09/07/2010 saat 22:20
kaynak kullanıcı

oy
0

Sadece soru hiçbir önceden belirlenmiş düzen onların söyleyen fark, bu nedenle bu Alakalı olmayabilir.

Perl kodu:

$list = [
    ['do', 're', 'fa', 'ti' ],
    ['do', 're', 'mi' ],
    ['do', 'la', 'ti', 'za' ],
    ['mi', 'fa' ],
    ['re', 'so', 'za' ]
];
%sid = map{($_,$n++)}qw/do re mi fa so la ti za/;

map{map{$k{$_}++}@$_}@$list;
push @$result,[$_,$k{$_}] for sort{$sid{$a}<=>$sid{$b}}keys%k;

print "[@$_]\n" for(@$result);

çıktı:

[do 3]
[re 3]
[mi 2]
[fa 2]
[so 1]
[la 1]
[ti 2]
[za 2]
Cevap 10/07/2010 saat 16:32
kaynak kullanıcı

oy
1

toplamak için bir karma kullanın.

my $notes= [[qw(do re fa ti)],
       [qw(do re mi)],
       [qw(do la ti za)],
       [qw(mi fa)],
       [qw(re so za)]];

my %out;
foreach my $list (@$notes)
{
  $out{$_}++ foreach @$list;
}

print "$_: $out{$_}\n" foreach sort keys %out;

Verim

do: 3
fa: 2
la: 1
mi: 2
re: 3
so: 1
ti: 2
za: 2

İstediğin buysa karma dışarı% kolayca listeye dönüştürülür.

my @newout;
push @newout,[$_,$out{$_}] foreach sort keys %out;
Cevap 21/04/2011 saat 16:54
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more