Баскетбольное решение
Давайте начнем с очень простого решения для печати сути последовательности. Это не касается специфики, которую вы добавили в свой вопрос, но это хорошая отправная точка:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
В отличие от .kv
, который преобразует свой инвокант в форму key1, value1, key2, value2, key3, value3, ...
, то есть 6 элементов, если его инвокант содержит 3 элемента, .pairs
преобразует свой инвокант в форму key1 => value1, key2 => value2, key3 => value3, ...
.
Я использовал .pairs
вместо .kv
частично, потому что это означало, что я мог бы ».gist
позже использовать в коде, чтобы без особых усилий получить хорошее key1 => value1
отображение для каждого элемента. Мы изменим это ниже, но это хорошее идиоматическое начало.
.head
И .tail
звонки идиоматических способ создать небольшие списки первых и последних N элементов из списка invocant ( при условии , что это не лень, больше о том , что в мес).
Учитывая это первоначальное решение, say seq-range-gist (0,1 ... Inf)[^10]
отображает:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
Далее, мы хотим иметь возможность «удалить только первый элемент ... из печатной продукции». К сожалению say seq-range-gist (0,1 ... Inf)[1..9]
отображает:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
Мы хотим, чтобы число слева от =>
сохранило нумерацию исходной последовательности. Чтобы включить это, мы отделяем основную последовательность от диапазона, который мы хотим извлечь. Мы добавляем второй параметр / аргумент @range
и добавляем [@range]
ко второй строке подпрограммы:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
Теперь мы можем написать say seq-range-gist (0,1 ... Inf), 1..9
для отображения:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
В своем вопросе вы использовали формат, aINDEX = VALUE
а не INDEX => VALUE
. Чтобы разрешить настройку сущности, мы добавляем третий &gist
стандартный параметр / аргумент и вызываем его вместо встроенного .gist
метода:
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
Обратите внимание, что вызовы "method" в теле seq-range-gist
sub теперь .&gist
не являются .gist
. Синтаксис .&foo
вызывает подпрограмму &foo
(которая обычно вызывается путем написания просто foo
), передавая вызов слева .
в качестве $_
аргумента подпрограмме.
Также обратите внимание, что я сделал &gist
параметр именованным, поставив перед ним символ :
.
Итак, теперь say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
отображает:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
Добавляя польский
Остальная часть этого ответа - бонусный материал для читателей, которым небезразлична полька.
say seq-range-gist (0, 1, 2, 3), ^3
дисплеи:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
К сожалению. И даже если бы было больше пар, чем головы и хвоста вместе, поэтому, по крайней мере, мы не получили повторяющихся линий, было бы бессмысленно использовать head, ..., tail
подход, чтобы исключить только один или два элемента. Давайте изменим последнее утверждение в под-теле, чтобы устранить эти проблемы:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
Далее, было бы неплохо, если бы сабвуфер сделал что-то полезное, если бы вызывался без диапазона или сути. Мы можем главным образом исправить, давая @range
и &gist
параметры , подходящие по умолчанию:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
Если @seq
это не ленив , то по @range
умолчанию в полном диапазоне @seq
. Если @seq
это бесконечно (в этом случае это также лениво), то по умолчанию до 100 по умолчанию. Но что, если @seq
это ленивый, но дает менее 100 определенных значений? Чтобы охватить этот случай, мы добавляем .grep: *.value.defined
к @pairs
декларации:
my @pairs = @seq.pairs[@range].grep: *.value.defined;
Еще одно простое улучшение - необязательные параметры головы и хвоста, приводящие к окончательному полированному решению:
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)
}