Mencetak seri matematika secara ringkas dalam Raku

9

Seri matematika, ambil contoh urutan berurutan yang diwakili di sini sebagai array:

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) };

Cetakan:

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

a8 =  8
a9 =  9

Pertanyaan saya: 1- Apakah ada cara sederhana untuk menghilangkan hanya elemen pertama yaitu a0 = 0dari hasil cetak?

2- Bisakah kode ini dibuat lebih idiomatis?

Terima kasih.

Lars Malmsteen
sumber
@DanBron Terima kasih atas komentarnya. Saya baru saja mengedit dan menguraikan posting asli.
Lars Malmsteen

Jawaban:

2

Solusi barebones

Mari kita mulai dengan solusi yang sangat sederhana untuk mencetak inti dari suatu urutan. Itu tidak berurusan dengan spesifik yang telah Anda tambahkan ke pertanyaan Anda, tetapi itu adalah titik awal yang baik:

sub seq-range-gist ( @seq ) {
  my @pairs = @seq.pairs;
  join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}

Tidak seperti .kv, yang mengubah invosinya ke dalam bentuk key1, value1, key2, value2, key3, value3, ..., yaitu 6 elemen jika invosinya mengandung 3 elemen, .pairsmengubah invosanya menjadi bentuk key1 => value1, key2 => value2, key3 => value3, ....

Saya menggunakan .pairsbukan .kvsebagian karena itu berarti saya bisa menggunakan ».gistnanti dalam kode untuk dengan mudah mendapatkan key1 => value1tampilan yang bagus untuk setiap elemen. Kami akan memodifikasi itu di bawah ini tetapi ini adalah awal yang bagus untuk memulai.

The .headdan .tailpanggilan adalah cara idiomatik untuk membuat daftar kecil dari yang pertama dan terakhir unsur N dari daftar invocant (asalkan jangan malas; lebih lanjut tentang bahwa dalam mo a).

Dengan solusi awal ini, say seq-range-gist (0,1 ... Inf)[^10]menampilkan:

0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9

Selanjutnya, kami ingin dapat "membuang elemen pertama ... dari hasil cetak". Sayangnya say seq-range-gist (0,1 ... Inf)[1..9]menampilkan:

0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9

Kami ingin nomor di sebelah kiri =>mempertahankan penomoran urutan asli. Untuk mengaktifkan ini, kami membagi urutan yang mendasarinya dari rentang yang ingin kami ekstrak. Kami menambahkan parameter / argumen kedua @range, dan menambahkan [@range]ke baris kedua dari sub:

sub seq-range-gist ( @seq, @range ) {
  my @pairs = @seq.pairs[@range];

Sekarang kita dapat menulis say seq-range-gist (0,1 ... Inf), 1..9untuk ditampilkan:

1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9

Dalam pertanyaan Anda, Anda menggunakan format aINDEX = VALUEdaripada INDEX => VALUE. Untuk membolehkan kustomisasi intisari, kami menambahkan &gistparameter / argumen rutin ketiga dan meminta itu alih-alih .gistmetode bawaan:

sub seq-range-gist ( @seq, @range, :&gist ) {
  my @pairs = @seq.pairs[@range];
  join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}

Perhatikan bagaimana pemanggilan "metode" dalam tubuh seq-range-gistsub sekarang .&gist, tidak .gist. Sintaks .&foomemanggil sub &foo (yang biasanya dipanggil dengan menulis adil foo), melewati pemohon di sebelah kiri .sebagai $_argumen ke sub.

Perhatikan juga bahwa saya telah membuat &gistparameter bernama satu dengan mendahului dengan a :.

Jadi sekarang say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }tampilkan:

a1 =  1
a2 =  2
a3 =  3
...
a8 =  8
a9 =  9

Menambahkan cat

Sisa dari jawaban ini adalah bahan bonus untuk pembaca yang peduli dengan bahasa Polandia.

say seq-range-gist (0, 1, 2, 3), ^3 menampilkan:

0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2

Ups. Dan bahkan jika ada lebih banyak pasangan daripada gabungan antara kepala dan ekor, jadi setidaknya kita tidak mendapatkan garis yang diulang, masih tidak ada gunanya menggunakan head, ..., tailpendekatan untuk menghilangkan hanya satu atau dua elemen. Mari kita ubah pernyataan terakhir di sub tubuh untuk menghilangkan masalah ini:

  join "\n",
    @pairs < $head + $tail + 3   # Of course, the 3 is a bit arbitrary
      ?? @pairs».&gist
      !! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)

Selanjutnya, alangkah baiknya jika sub melakukan sesuatu yang berguna jika dipanggil tanpa range atau intisari. Kami sebagian besar dapat memperbaikinya dengan memberikan @rangedan &gistparameter default yang sesuai:

sub seq-range-gist (
  @seq,
  @range = @seq.is-lazy ?? ^100 !! ^@seq,
  :&gist = { .gist }
) {

Jika @seqini tidak malas , maka @rangedefault ke berbagai @seq. Jika @seqtidak terbatas (dalam hal ini juga malas), maka standar hingga 100 baik-baik saja. Tetapi bagaimana jika @seqmalas tetapi menghasilkan kurang dari 100 nilai yang ditentukan? Untuk membahas kasus ini kami menambahkan .grep: *.value.definedke @pairsdeklarasi:

  my @pairs = @seq.pairs[@range].grep: *.value.defined;

Peningkatan sederhana lainnya adalah parameter kepala dan ekor opsional, yang mengarah ke solusi akhir yang dipoles:

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
sumber
Solusi minimal berfungsi dengan sangat baik dan juga idiomatis. Dalam solusi saya, saya harus menggunakan variabel 'flag' untuk memperhitungkan ...bagian yang membuatnya terlihat seperti program C. Jadi ini menjawab kedua bagian pertanyaan saya, sungguh. Adapun solusi 'komprehensif', itu terlihat agak menakutkan, sungguh.
Lars Malmsteen
Terima kasih atas tanggapan Anda dan menerima jawaban saya @LarsMalmsteen. Yang mengatakan, saya sepenuhnya menulis ulang jawaban saya dan merasa jauh lebih baik. Saya telah menjatuhkan solusi 'komprehensif' - saya telah pergi jauh ke rumput liar dengan itu! - tapi saya juga sepenuhnya menulis ulang "solusi minimal" dan penjelasan yang menyertainya. Saya melakukannya sebagian besar untuk pembaca lain di kemudian hari, tetapi Anda mungkin mendapatkan nilai dari membaca jawaban baru.
raiph
7

Anda dapat melewati nilai N pertama pada setiap Iterable atau Sequencedengan skip:

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

Jika Anda tidak menentukan nomor, itu akan melewati hanya satu elemen.

Elizabeth Mattijsen
sumber
The skiptampaknya untuk menghapus hanya ouput yaitu elemen dengan indeks 0 (a0) sisa-sisa. Saya sudah mencoba @seq:deletedan baru saja mengganti elemen 0 dengan(Any)
Lars Malmsteen
Memang. Hanya skipakan bertindak seolah-olah elemen yang dilewati tidak ada. Ini mungkin atau mungkin bukan yang Anda inginkan :-)
Elizabeth Mattijsen
Ketika saya meletakkan skipdi antara sehingga terbaca: for @seq[^10].skip(0).kvitu benar - benar tidak melewatkan elemen 0 dan tidak masalah jika saya berikan sebagai argumen ke skip1 atau 2, itu hanya mendistorsi lebih jauh. Saya perlu cara praktis untuk menghapus elemen 0 dari bawah ke atas.
Lars Malmsteen
1
Mungkin for @seq[^10].kv.skip(2)apa yang Anda cari?
Elizabeth Mattijsen
Ya itu berhasil. Sebenarnya saya mencoba meletakkan skipsetelah .kvtapi menggunakan argumen selain 2, jadi tidak berhasil. Terima kasih atas solusinya.
Lars Malmsteen
7

Ini mungkin sedikit lebih idiomatis:

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

Anda tidak perlu menggunakan variabel leksikal dalam urutan; salah satu Whateveratau variabel placeholder dapat digunakan dengan aman dalam urutan. Kemudian Anda cukup memilih elemen dari urutan yang ingin Anda cetak. Yang kembali«(0 1 2 3)(7 8 9 10)␤»

jjmerelo
sumber
Terima kasih atas jawabannya. The whateveroperator refreshening tapi output seri / berurutan tidak mengatasi masalah utama. Saya ingin mencetak seri seperti yang terlihat pada buku teks matematika, yaitu dengan ...notasi di antaranya.
Lars Malmsteen
@ LarsMalmsteen, OK, saya akan mengeditnya
jjmerelo