Rozwiązanie typu barebones
Zacznijmy od bardzo prostego rozwiązania do drukowania streszczenia sekwencji. Nie zajmuje się szczegółami dodanymi do pytania, ale jest dobrym punktem wyjścia:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
W przeciwieństwie do tego .kv
, który konwertuje swojego wywoływacza do postaci key1, value1, key2, value2, key3, value3, ...
, tj. 6 elementów, jeśli jego wywoływacz zawiera 3 elementy, .pairs
przekształca swojego wywoływacza do postaci key1 => value1, key2 => value2, key3 => value3, ...
.
Użyłem .pairs
zamiast .kv
częściowo, ponieważ oznaczało to, że mogłem użyć ».gist
później w kodzie, aby bez wysiłku uzyskać ładny key1 => value1
wyświetlacz dla każdego elementu. Zmodyfikujemy to poniżej, ale to dobry początek idiomatyczny.
.head
I .tail
połączenia są idiomatyczne sposób na tworzenie małych list pierwszych i ostatnich n elementów z listy invocant (pod warunkiem, że nie jest leniwy, więcej na ten temat w MO).
Biorąc pod uwagę to wstępne rozwiązanie, say seq-range-gist (0,1 ... Inf)[^10]
wyświetla:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Następnie chcemy móc „upuścić tylko pierwszy element ... z wydruku”. Niestety say seq-range-gist (0,1 ... Inf)[1..9]
wyświetla:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Chcemy, aby liczba po lewej stronie =>
zachowała numerację oryginalnej sekwencji. Aby to umożliwić, rozdzieliliśmy leżącą u podstaw sekwencję z zakresu, który chcemy wyodrębnić. Dodajemy drugi parametr / argument @range
i dołączamy [@range]
do drugiego wiersza sub:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Teraz możemy napisać say seq-range-gist (0,1 ... Inf), 1..9
do wyświetlenia:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
W swoim pytaniu użyłeś formatu aINDEX = VALUE
zamiast INDEX => VALUE
. Aby umożliwić dostosowanie GIST, dodajemy trzeci &gist
rutynowy parametr / argument i wywołujemy go zamiast wbudowanej .gist
metody:
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Zauważ, że seq-range-gist
teraz .&gist
nie są wywołania „metody” w treści sub .gist
. Składnia .&foo
wywołuje podrzędny &foo
(który jest zwykle wywoływany przez napisanie po prostu foo
), przekazując wywoływacza po lewej stronie .
jako $_
argument do podrzędnego.
Zauważ też, że nadałem &gist
parametrowi nazwę, poprzedzając go znakiem :
.
Teraz say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
wyświetla:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Dodawanie polskiego
Pozostała część tej odpowiedzi jest dodatkowym materiałem dla czytelników, którym zależy na języku polskim.
say seq-range-gist (0, 1, 2, 3), ^3
wyświetla:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
Ups I nawet gdyby było więcej par niż głowa i ogon łącznie, więc przynajmniej nie otrzymywaliśmy powtarzających się linii, nadal byłoby bezcelowe stosowanie head, ..., tail
podejścia, aby uniknąć tylko jednego lub dwóch elementów. Zmieńmy ostatnią instrukcję w treści podrzędnej, aby wyeliminować następujące problemy:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
Następnie byłoby miło, gdyby subwoofer zrobił coś pożytecznego, gdyby został wywołany bez zasięgu lub istoty. W większości przypadków możemy to naprawić, nadając parametrom @range
i &gist
odpowiednie wartości domyślne:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Jeśli nie@seq
jest leniwy , domyślnie jest to pełny zakres . Jeśli jest nieskończony (w takim przypadku jest również leniwy), to domyślnie do 100 jest w porządku. Ale co, jeśli jest leniwy, ale daje mniej niż 100 zdefiniowanych wartości? Aby uwzględnić tę sprawę, dołączamy do deklaracji: @range
@seq
@seq
@seq
.grep: *.value.defined
@pairs
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Kolejnym prostym ulepszeniem byłyby opcjonalne parametry głowy i ogona, prowadzące do ostatecznego dopracowanego rozwiązania:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:$head = 3,
:$tail = 2,
:&gist = { .gist }
) {
my @pairs = @seq.pairs[@range].grep: *.value.defined;
join "\n",
@pairs <= $head + $tail + 2
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
}