Друга математична серія в Раку


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 Дякую за коментар. Я щойно редагував і деталізував оригінальний пост.
— Lars Malmsteen

Відповіді:


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
}

Зверніть увагу, як зараз виклики "методу" в тілі seq-range-gistпідрозділу .&gist, ні .gist. Синтаксис .&fooвикликає суб &foo (який , як правило , викликається шляхом запису тільки foo), передаючи invocant на зліва від .як $_аргумент на південь.

Зауважте також, що я зробив &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)
}

Мінімальне рішення працює досить добре, а також пристойно ідіоматично. У своєму рішенні я повинен був вдатися до змінної 'flag', щоб рахуватися з ...частиною, що викликає її схожість на програму C. Отже, це відповідає дійсно на обидві частини мого питання. Що стосується "всебічного" рішення, то воно виглядає дещо залякано.
— Lars Malmsteen

Дякуємо за Ваш відгук та прийняли мою відповідь @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-й елемент з нуля.
— Lars Malmsteen

1
Можливо, for @seq[^10].kv.skip(2)це те, що ви шукаєте?
— Елізабет Маттійсен

Так, це робить роботу. Насправді я спробував поставити skipпісля, .kvале за допомогою аргументів, відмінних від 2, тому це не вийшло. Дякую за рішення.
— Lars Malmsteen

7

Це може бути трохи ідіоматичнішим:

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

Вам не потрібно використовувати лексичну змінну в послідовності; або Whateverабо шаблонні змінні можуть бути безпечно використані в послідовності. Тоді ви можете просто вибрати елементи послідовності, яку ви хочете надрукувати. Який повертається«(0 1 2 3)(7 8 9 10)␤»


Дякую за відповідь. whateverОператор refreshening але вихід серії / послідовність не вирішує головне питання. Я хотів би надрукувати серію так, як їх бачать у підручниках з математики, тобто з ...позначеннями між ними.
— Lars Malmsteen

@LarsMalmsteen, Добре, я це відредагую
— jjmerelo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.