Краткая печать математических серий в Раку

9

Математическая серия, например, последовательная последовательность, представленная здесь в виде массива:

my @seq = my $a=0, {++$a} ... *;
for @seq[^10].kv {state $f=0; ($^k < 4 or $^k > 7) ?? say "a$^k =  "  ~ $^v !! (say "..." if $f ne 1; $f=1) };

Печать:

a0 =  0
a1 =  1
a2 =  2
...

a8 =  8
a9 =  9

Мои вопросы: 1- Есть ли простой способ удалить только первый элемент, то есть a0 = 0из распечатки?

2- Можно ли сделать этот код более идиоматичным?

Спасибо.

Ларс Мальмстин
источник
@DanBron Спасибо за комментарий. Я только что отредактировал и развил исходный пост.
Ларс Мальмстин

Ответы:

2

Баскетбольное решение

Давайте начнем с очень простого решения для печати сути последовательности. Это не касается специфики, которую вы добавили в свой вопрос, но это хорошая отправная точка:

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-gistsub теперь .&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)
}
raiph
источник
Минимальное решение работает вполне нормально и прилично идиоматично. В моем решении мне пришлось прибегнуть к переменной 'flag', чтобы считаться с ...частью, заставляющей ее больше походить на C-программу. Так что это действительно отвечает на обе части моего вопроса. Что касается «комплексного» решения, то оно выглядит немного пугающим.
Ларс Мальмстин
Спасибо за ваш отзыв и принятие моего ответа @LarsMalmsteen. Тем не менее, я полностью переписал свой ответ и чувствую, что он намного лучше. Я отбросил «комплексное» решение - с этим я ушел далеко в сорняки! - но я также полностью переписал «минимальное решение» и сопутствующее объяснение. Я сделал это главным образом для других более поздних читателей, но вы могли бы получить некоторую пользу от чтения нового ответа.
raiph
7

Вы можете пропустить первые N значений для любого Iterable или Sequenceс skip:

for (^5).skip(3) {
    .say
}
# 3
# 4

Если вы не укажете число, будет пропущен только один элемент.

Элизабет Маттийсен
источник
skip, Кажется, удалить только Ouput то есть элемент с индексом 0 - й (а0) остается. Я попытался, @seq:deleteи он просто заменил 0-й элемент на(Any)
Ларс Мальмстин
Верно. skipБудет просто действовать , как будто пропущенные элементы не существуют. Это может или не может быть то, что вы хотите :-)
Элизабет Маттийсен
Когда я помещаю их skipмежду ними так, чтобы они читали: for @seq[^10].skip(0).kvон буквально не пропускает 0-й элемент, и не имеет значения, если я приведу в качестве аргумента skip1 или 2, он просто еще больше искажает. Мне нужен практический способ удалить 0-й элемент с нуля.
Ларс Мальмстин
1
Возможно, for @seq[^10].kv.skip(2)это то, что вы ищете?
Елизавета Маттийсен
Да, это делает работу. На самом деле я попытался поставить skipпосле, .kvно используя аргументы, отличные от 2, так что это не сработало. Спасибо за решение.
Ларс Мальмстин
7

Это может быть немного более идиоматическим:

my @seq = 0, *+1 ... *;
say @seq[^4], @seq[7..10]

Вам не нужно использовать лексическую переменную внутри последовательности; либо Whateverили шаблонные переменные могут быть безопасно использованы в последовательности. Затем вы можете просто выбрать элементы последовательности, которую вы хотите напечатать. Который возвращается«(0 1 2 3)(7 8 9 10)␤»

jjmerelo
источник
Спасибо за ответ. whateverОператор refreshening но выход серии / последовательность не решает главный вопрос. Я хотел бы напечатать серию, как они видны на математических учебниках, то есть с ...пометкой между ними.
Ларс Мальмстин
@LarsMalmsteen, хорошо, я отредактирую это
jjmerelo