数学シリーズを楽で簡潔に印刷する


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, ...。つまり、その呼び出し元が3つの要素を含む場合、6つの要素は、.pairsその呼び出し元をフォームに変換しkey1 => value1, key2 => value2, key3 => value3, ...ます。

一部の.pairs代わりに使用しまし.kvた。これは».gist、後でコード内で使用するだけで、key1 => value1各要素の表示を簡単にできるようになるためです。以下で変更しますが、これは慣用的な出発点として適切です。

通話は(;よりカ月でそのことについて、それは怠惰ではありません提供)インボカントリストから最初と最後のN個の要素の小さなリストを作成するための慣用的な方法です。.head.tail

この最初のソリューションが与えられると、次のように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

の左側の=>番号に元のシーケンスの番号付けを保持させたい。これを有効にするには、抽出する範囲から基になるシーケンスを分割します。2番目のパラメーター/引数@rangeを追加[@range]し、サブの2行目に追加します。

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。要旨のカスタマイズを可能にするために、3番目の&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-gistsub の本体の「メソッド」呼び出しが、.&gistではなくになって.gistいることに注意してください。構文.&foosubを 呼び出し&foo(通常はjustを書き込むことで呼び出されますfoo)、その左側の呼び出し元を引数.としてsubに渡し$_ます。

また、&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, ..., tail1つまたは2つの要素だけを削除するアプローチを使用しても意味がありません。サブボディの最後のステートメントを変更して、これらの問題を排除しましょう。

  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遅延ない 場合、デフォルトでの全範囲になります。が無限の場合(この場合も遅延です)、最大100のデフォルトで問題ありません。しかし、怠惰であるにもかかわらず、定義された値が100未満の場合はどうなりますか?このケースをカバーするために、宣言に追加します。@range@seq@seq@seq.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)
}

最小限のソリューションは非常にうまく機能し、まともな慣用的でもあります。私の解決策では、「フラグ」変数を使用して...、Cプログラムのように見える部分を考慮しなければなりませんでした。だから、これは私の質問の両方の部分に本当に答えます。「包括的な」ソリューションに関しては、それは実際には少し威圧的に見えます。
Lars Malmsteen

あなたのフィードバックをありがとう、私の答え@LarsMalmsteenを受け入れてください。そうは言っても、私は自分の答えを完全に書き直し、はるかに優れていると感じています。私は「包括的な」ソリューションを削除しました-私はそれで雑草に遠く行きました!-しかし、「最小限の解決策」とそれに伴う説明も完全に書き直しました。私は主に後の読者のためにそうしましたが、あなたは新しい答えを読むことから何らかの価値を得るかもしれません。
Raifは

7

最初のN個の値は、次のいずれ IterableSequenceでスキップできますskip

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

数値を指定しない場合、1つの要素のみがスキップされます。


skip0番目のインデックス(A0)遺跡でちょうど出力に含ますなわち要素を削除しているようです。私が試し@seq:deleteたところ、0番目の要素が次のように置き換えられました(Any)
Lars Malmsteen

確かに。skipは、スキップされた要素が存在しないかのように動作します。これはあなたが望むものかもしれないし、そうでないかもしれません:-)
Elizabeth Mattijsen

skipそれを読むように間に置いたとき:for @seq[^10].skip(0).kvそれは文字通り 0番目の要素をスキップせず、引数としてskip1または2 を与えるかどうかは関係ありません。0番目の要素をゼロから削除する実用的な方法が必要です。
Lars Malmsteen

1
おそらくfor @seq[^10].kv.skip(2)あなたが探しているものは何ですか?
Elizabeth Mattijsen

はい、それは仕事をします。実際に私は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されているが、シリーズ/シーケンス出力は、メインの問題に対処しません。シリーズは、数学のtexbookで見られるように、つまり...間に表記を含めて印刷したいと思います。
Lars Malmsteen

@ LarsMalmsteen、OK、編集します
jjmerelo '10
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.