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


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.