Portál AbcLinuxu, 24. říjen 2017 00:30

Dotaz: požírání matice

10.9. 19:56 RM
požírání matice
Přečteno: 1012×
Odpovědět | Admin
Protože o víkendu u sousedů na "růtu" programátoři požírali (možná ještě požírají) matici - stylem od levého horního rohu spirálovitě do středu - a používali k tomu různé jazyky, které já neznam, chtěl bych se zeptat jak na to jít třeba v Perlu 6, který právě studuji? Ale klidně i jiné jazyky, pokud to bude mít rozumnou délku, případně nějaký ten vtip k tomu ;). Jako ukázku dávám svůj kód v Perlu 5.
$a = [ [1, 3, 5, 7, 6],
       [2, 5, 8, 2, 5],
       [5, 7, 8, 1, 2],
       [4, 2, 3, 5, 6],
       [8, 6, 5, 4, 2] ];

while(@{$a}) {
    push @list, @{shift $a};
    push @list, pop($a->[$j++])  while @{$a->[$j]}; $j--;
    push @list, reverse(@{pop $a});
    push @list, shift($a->[$j])  while $j>0 && @{$a->[--$j]};
}
print "@list";

Řešení dotazu:


Nástroje: Začni sledovat (1) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

wamba avatar 10.9. 20:46 wamba | skóre: 37 | blog: wamba
Rozbalit Rozbalit vše Re: požírání matice
Odpovědět | | Sbalit | Link | Blokovat | Admin
Např. tvá verze pro Perl 6
sub snake ($matrix is rw) {
    my @snake;
    while $matrix {
        @snake.push: |.shift with $matrix;                 #left
        @snake.push: |$_».pop with $matrix;                #down
        @snake.push: |.pop.reverse with $matrix;           #right
        @snake.push: |$_».shift.reverse with $matrix;      #up
    }
    @snake
}
Trochu vylepšená verze
sub snake2 ($matrix is rw) {
    my @snake;
    my @take = |(
        { .shift },                 #left
        { .map: *.pop },            #down
        { .pop.reverse },           #right
        { .map( *.shift ).reverse } #up
    ) xx *;
    while $matrix {
        my &action = @take.shift;
        @snake.push: |$matrix.&action;
    }
    @snake
}
Verze s otočením:
sub snake3 (@matrix is copy) {
    my @snake;
    while @matrix {
        @snake.push: |@matrix.shift;
        @matrix = reverse [Z,] |@matrix;
    }
    @snake
}
This would have been so hard to fix when you don't know that there is in fact an easy fix.
11.9. 13:08 RM
Rozbalit Rozbalit vše Re: požírání matice
Díky, pěkná ukázka.
11.9. 20:12 RM
Rozbalit Rozbalit vše Re: požírání matice
Takhle by to v Perlu 5 vypadalo s map místo while:
while(@{$a}) {
     push @list, @{shift $a};
     push @list, map { pop $_ } @{$a};
     push @list, reverse(@{pop $a});
     push @list, reverse map { shift $_ } @{$a}
}
Vypadá to lépe, jen za cenu dalšího reverse().
wamba avatar 11.9. 21:19 wamba | skóre: 37 | blog: wamba
Rozbalit Rozbalit vše Re: požírání matice
Ještě u té druhé verze je rozumné mít @take jako nepovinný parametr
my @spiral = (
    { .shift },                  #right
    { .map: *.pop },             #down
    { .pop.reverse },            #left
    { .map( *.shift ).reverse }, #up
);

sub snake2 ( @matrix, :@take is copy = |@spiral xx * ) {
    my @snake;
    while @matrix[0] {
        my &action = @take.shift;
        @snake.push: |@matrix.&action;
        #say @matrix;
    }
    @snake;
}
Pak s tím lze dělat skopičiny jako opačná spirála začínající v pravém horním rohu:
my @reverse-spiral = |@spiral.rotate.map( { &reverse o $_ } ).reverse xx *;
say $matrix.&snake2(take => @reverse-spiral);
nebo třeba takovýto had:
my @right-left-down-up = |(
    { .shift },                   #right
    { .shift.reverse },           #left
    { .map: *.shift   },          #down
    { .map( *.shift ).reverse  }, #up
) xx *;                           #repeat

say $matrix.&snake2(take => @right-left-down-up);
This would have been so hard to fix when you don't know that there is in fact an easy fix.
11.9. 23:45 RM
Rozbalit Rozbalit vše Re: požírání matice
Díky, těch informací je zatím poskromnu a z dokumentace Perlu 6 se to těžko dedukuje. Myslím, že princip, jak chytře pracovat s vícerozměrným polem, je mi už celkem jasnej. Dál už se tím nějak prokoušu.
12.9. 09:12 RM
Rozbalit Rozbalit vše Re: požírání matice
Co znamená to o za &reverse? Jako operátor to nemůžu najít.
wamba avatar 12.9. 09:31 wamba | skóre: 37 | blog: wamba
Rozbalit Rozbalit vše Re: požírání matice
Je to skládaní funkcí viz role Callable. Máš pravdu v dokumentaci se to blbě hledá.
This would have been so hard to fix when you don't know that there is in fact an easy fix.
Řešení 1× (Marek Stopka)
10.9. 20:48 NN
Rozbalit Rozbalit vše Re: požírání matice
Odpovědět | | Sbalit | Link | Blokovat | Admin
Poradna neslouzi k vypracovavani domacich ukolu. Kdyz se to resilo na rootu proc lezes sem?
10.9. 21:03 RM
Rozbalit Rozbalit vše Re: požírání matice
Protože vím, že o Perl6 se tu už někdo zajímá a mám tak naději, že zde dostanu co hledám ;) První větu nechápu.
14.9. 13:54 kolemjdouci
Rozbalit Rozbalit vše Re: požírání matice
Odpovědět | | Sbalit | Link | Blokovat | Admin
Nezivim se jako programator jen obcas neco napisu, ale kdyz vidm takovy zhovadili kod dere se mi na mysl otazka: "Co vas, proboha, lidi nuti pouzivat takove 'zhovadile' zapisy?" Neberte to jako urazku spis jde jen o zamysleni a vas nazor na vec. Netvrdte ze jde o to usetrit 10radku kodu, ktery by zase vedl k lepsi prehlednosti.
14.9. 13:56 NN
Rozbalit Rozbalit vše Re: požírání matice
To je proste Perl, takto to vypada i normalne ;) ..
14.9. 14:12 kolemjdouci
Rozbalit Rozbalit vše Re: požírání matice
Koukl jsem na rootu na to vlakno a tam je podobny zapis i v Pythonu. No nic
14.9. 19:14 RM
Rozbalit Rozbalit vše Re: požírání matice
Tak jsou to skriptovací jazyky, tak bych očekával používání nějakých větších dílčích celků a ne jen elementární instrukce cyklu a pole s indexem. V dotazu mi šlo o nějakou představu, kam se to posunulo u Perlu6, který nabízí daleko větší abstrakci než Perl5, tam bylo možné oproti běžnému imperativnímu programování jen trochu kouzlit se seznamy (což jsem v ukázce trochu využil;). Uvedený příklad s hadem je samozřejmě triviální, jen posloužil jako příklad.
14.9. 19:39 RM
Rozbalit Rozbalit vše Re: požírání matice
Možná by vás mohl přesvědčit složitější příklad, také převzatý z z rootu, který jsem si jen mírně upravil podle svého přání:
my @a = [ [  (0,   0), (100,  0), (100,  44),  (62,  44),   (0,  38), (1, 3) ],
          [ (94, 100),  (28, 50),  (62,  44), (100,  44), (100, 100) ],
          [  (0,  44),  (28, 50),  (94, 100),   (0, 100), (3, 1)     ],
          [ (28,  50),   (0, 44),   (0,  38),  (62,  44)             ]  ]	;


for 1..+@a -> $lineo {
    my $b=@a.shift;

    my $aflat=@a.List.flat.map({.Str});
    my $bflat=$b.flat.map({.Str}).cache;
    my $intersection = $aflat  (&)  $bflat;

    say "$lineo: ", $intersection{$bflat.List}.pairs.Set.keys.sort;

    @a.push: $b
}
Vůbec není nutné uvažovat o nějakém procházení pole a splněné podmínce, ale prostě se vytvoří vždy dvě množiny (jeden řádek a zbytek) na kterých se udělá průnik, a tím se zjistí, jaké dvojice se vyskytují na dalších řádcích. -- Možná by to šlo provést lépe, teprve začínám ;).
15.9. 16:45 gll
Rozbalit Rozbalit vše Re: požírání matice
jsem autorem toho posledního kódu na rootu. Tohle by šlo v Perlu6 řešit mnohem elegantněji pomocí hyperoperátoru. Z hlavy to nedám a teď nemám možnost to zkoušet. Jsou tu větší experti na Perl 6. Rád bych viděl jejich řešení.
15.9. 17:01 gll
Rozbalit Rozbalit vše Re: požírání matice
**elegantněji než to mé řešení v Pythonu.
15.9. 20:24 RM
Rozbalit Rozbalit vše Re: požírání matice
Také budu rád, když někdo ukáže lepší řešení. Já jsem si zatím jenom hrál s "hašovitými" typy a tohle mne napadlo.
wamba avatar 15.9. 23:39 wamba | skóre: 37 | blog: wamba
Rozbalit Rozbalit vše Re: požírání matice
Tak přikládám moje řešení v Perlu 6
my @a =  [
    [(0, 0), (100, 0), (100, 44), (62, 44), (0, 38)],
    [(94, 100), (28, 50), (62, 44), (100, 44), (100, 100)],
    [(0, 44), (28, 50), (94, 100), (0, 100)],
    [(28, 50), (0, 44), (0, 38), (62, 44)]
];

my @result;

for ^@a.elems .combinations(2) -> ($i, $j) {
    next unless @a[$i].any eqv @a[$j].any;

    @result[$i].push: $j;
    @result[$j].push: $i;
}

@result.pairs».say;
Jestli si myslel, že by šlo použít např. X∩, tak jsem narazil na celkem dost problémů.

Nejvážnější je, že se to chová poněkud divně:
dd (set(1),set(2)) X∩ set(2),
vypíše:
(set(set(1),set(2)), set(set(2))).Seq
Namísto @a[$i].any eqv @a[$j].any; bych mohl použít [or] @a[$i].list Xeqv @a[$j].list;, kdybych moc chtěl metaoperátory, ale takhle se mi to zdá přímější. Navíc ta část s Junction by se měla vyhodnocovat paralelně.
This would have been so hard to fix when you don't know that there is in fact an easy fix.
16.9. 11:47 RM
Rozbalit Rozbalit vše Re: požírání matice
Jenom přemýšlím, jak moc to splňuje požadavek absence "naivního prohledávání v cyklu", když řádky (seznamy) se stejně porovnávají každý s každým :). Asi jsem to zadání bral moc doslovně.
16.9. 22:34 RM
Rozbalit Rozbalit vše Re: požírání matice
Chvíli jsem zkoumal metaoperátory a spíš mi přijde, že to "divné" chování je vlastnost. Ten průnik nad "hešovitým" typem se chová tak, jakoby se jednalo o hash se stejným klíčem, proto set(set(2)) a ne set(set(2), set(2)) -- dojde ke sloučení, jakoby to byly stejné klíče. Ale možná to blbě chápu.
20.9. 11:18 zero
Rozbalit Rozbalit vše Re: požírání matice
Odpovědět | | Sbalit | Link | Blokovat | Admin
Čistě pro zajímavost, v jazyce J by šlo funkci (spiral) napsat třeba takto:
spiral =: 3 : 0
M =. y
r =. ''
while. #M > 0 do.
  r =. r, {.M
  M =. }.M
  M =. |. |: M
end.
r
)
Určitě to není nejkratší zápis, zato je snadno pochopitelný :)

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.