Terlepas dari semua jawaban yang menunjukkan bagaimana menyelesaikannya dengan parse ... Mengapa Anda perlu menyimpan jenis bahasa dalam karakter string? Jawaban Martin Mächler patut mendapat lebih banyak dukungan.
Petr Matousu
7
@PetrMatousu terima kasih. Ya, saya terkejut melihat bagaimana informasi yang salah tersebar di SO sekarang .. oleh orang-orang yang memilih eval(parse(text = *)) solusi palsu.
Martin Mächler
2
Saya ingin menjalankan skrip dalam bentuk:, QQ = c('11','12','13','21','22','23')yaitu: QQ = c (..., 'ij', ..) dengan i, j yang bervariasi pada rentang yang mungkin berbeda dari yang dijalankan ke yang dijalankan. Untuk contoh ini dan yang serupa, saya dapat menulis skrip sebagai paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), dan opsi eval(parse(text=...))menciptakan vektor QQ di lingkungan kerja sesuai skrip. Apa yang akan menjadi cara pengkode R yang tepat untuk melakukan ini, jika tidak dengan "text = ..."?
VictorZurkowski
Jawaban:
419
The eval()Fungsi mengevaluasi ekspresi, tetapi "5+5"adalah sebuah string, bukan ekspresi. Gunakan parse()dengan text=<string>untuk mengubah string menjadi ekspresi:
Panggilan eval()memanggil banyak perilaku, beberapa tidak segera jelas:
> class(eval(parse(text="5+5")))[1]"numeric"> class(eval(parse(text="gray")))[1]"function"> class(eval(parse(text="blue")))
Error in eval(expr, envir, enclos): object 'blue' not found
Seperti yang dicatat Shane di bawah, "Anda harus menentukan bahwa inputnya berupa teks, karena parse mengharapkan file secara default"
PatrickT
1
efek samping dari penggunaan eval (parse) harus ditentukan. Misalnya, jika Anda memiliki nama variabel yang ditentukan sebelumnya sama dengan "David" dan Anda menetapkan kembali menggunakan eval (parse (text = "name") == "Alexander", Anda akan mendapatkan kesalahan karena eval & parse tidak mengembalikan Ekspresi R yang dapat dievaluasi
Crt
1
@NelsonGon: ekspresi unevaluated dibangun menggunakan quote(), bquote()atau alat yang lebih canggih yang disediakan oleh rlangpaket.
Artem Sokolov
@ Artemokolon Terima kasih, saya entah bagaimana terus kembali ke pertanyaan ini mencari alternatif. Saya telah melihat rlangtetapi yang paling dekat saya temukan adalah parse_exprpanggilan parse_exprsyang pada gilirannya sama dengan menggunakan parsedan membungkusnya evalyang tampaknya sama dengan yang dilakukan di sini. Saya tidak yakin apa keuntungan menggunakan rlang.
NelsonGon
1
@NelsonGon: with rlang, Anda akan bekerja secara langsung dengan ekspresi, bukan string. Tidak perlu langkah parse. Ini memiliki dua keunggulan. 1. Manipulasi ekspresi akan selalu menghasilkan ekspresi yang valid. Manipulasi string hanya akan menghasilkan string yang valid. Anda tidak akan tahu apakah itu ekspresi yang valid hingga Anda menguraikannya. 2. Tidak ada yang setara dengan substitute()kelas fungsi di dunia string, yang sangat membatasi kemampuan Anda untuk memanipulasi panggilan fungsi. Pertimbangkan pembungkus glm ini . Seperti apa bentuk string yang setara?
Artem Sokolov
100
Anda dapat menggunakan parse()fungsi ini untuk mengubah karakter menjadi ekspresi. Anda perlu menentukan bahwa input adalah teks, karena parse mengharapkan file secara default:
> fortunes :: fortune ("answer is parse") Jika jawabannya parse () Anda biasanya harus memikirkan kembali pertanyaannya. - Thomas Lumley R-help (Februari 2005)>
Martin Mächler
13
@ MartinMächler Sungguh ironis, karena paket inti R selalu digunakan parse! github.com/wch/r-source/…
geneorama
49
Maaf tapi saya tidak mengerti mengapa terlalu banyak orang berpikir string adalah sesuatu yang bisa dievaluasi. Anda harus mengubah pola pikir Anda, sungguh. Lupakan semua koneksi antara string di satu sisi dan ekspresi, panggilan, evaluasi di sisi lain.
Koneksi (mungkin) hanya melalui parse(text = ....)dan semua programmer R yang baik harus tahu bahwa ini jarang cara yang efisien atau aman untuk membangun ekspresi (atau panggilan). Sebaliknya mempelajari lebih lanjut tentang substitute(), quote(), dan mungkin kekuatan menggunakan do.call(substitute, ......).
fortunes::fortune("answer is parse")# If the answer is parse() you should usually rethink the question.# -- Thomas Lumley# R-help (February 2005)
Dec.2017: Ok, ini sebuah contoh (dalam komentar, tidak ada format yang bagus):
dan jika Anda mendapatkan lebih berpengalaman Anda akan belajar bahwa q5adalah "call"sedangkan e5adalah "expression", dan bahkan yang e5[[1]]identik dengan q5:
bisakah kamu memberikan contoh? mungkin Anda bisa menunjukkan kepada kami cara "bertahan" hingga 5 + 5 pada objek r, lalu mengevaluasi nanti, menggunakan kutipan dan pengganti daripada karakter dan eval (parse (text =)?
Richard DiSalvo
3
Saya mungkin sedikit tersesat. Pada poin apa Anda mendapatkan 10? Atau bukan itu intinya?
Nick S
@RichardDiSalvo: ya, di q5 <- quote(5+5)atas adalah ekspresi (sebenarnya "panggilan") 5+5dan itu adalah objek R, tetapi bukan string. Anda dapat mengevaluasinya kapan saja. Lagi: menggunakan, kutipan (), pengganti (), ... alih-alih parse membuat panggilan atau ekspresi secara langsung dan lebih efisien daripada melalui parse (teks =.). Menggunakan eval()baik-baik saja, menggunakan parse(text=*)rentan terhadap kesalahan dan kadang-kadang cukup tidak efisien dibandingkan dengan panggilan konstruksi dan memanipulasi mereka .. @Nick S: Ini eval(q5) atau eval(e5) dalam contoh yang sedang berjalan
Martin Mächler
@NickS: Untuk mendapatkan 10, Anda mengevaluasi panggilan / ekspresi, yaitu, panggil eval(.)saja. Maksud saya adalah bahwa orang tidak boleh menggunakan parse(text=.)melainkan quote(.)dll, untuk membangun panggilan yang nantinya akan eval()diedit.
Martin Mächler
2
eval(quote())memang berfungsi dalam beberapa kasus tetapi akan gagal untuk beberapa kasus di mana eval(parse())akan bekerja dengan baik.
NelsonGon
18
Atau, Anda dapat menggunakan evalsdari panderpaket saya untuk menangkap output dan semua peringatan, kesalahan, dan pesan lainnya bersama dengan hasil mentah:
Fungsi bagus; mengisi lubang yang ditinggalkan evaluate::evaluatedengan benar-benar mengembalikan objek hasil; yang membuat fungsi Anda cocok untuk digunakan menelepon melalui mclapply. Saya harap fitur itu tetap ada!
russellpierce
Terima kasih, @ rpierce. Fungsi ini awalnya ditulis pada tahun 2011 sebagai bagian dari rapportpaket kami , dan telah secara aktif dipertahankan sejak saat itu karena banyak digunakan dalam layanan rapporter.net kami selain beberapa proyek lain juga - jadi saya yakin itu akan tetap dipertahankan untuk sementara :) Saya senang Anda menemukan itu berguna, terima kasih atas tanggapan Anda.
daroczig
14
Saat ini Anda juga dapat menggunakan lazy_evalfungsi dari lazyevalpaket.
Datang ke sini mencari rlangjawaban tetapi bagaimana jika ada keuntungan dari alternatif ini? Sebenarnya, pemeriksaan ketat terhadap kode yang digunakan menunjukkan bahwa sebenarnya menggunakan eval(parse(....))yang ingin saya hindari.
NelsonGon
4
Tidak hanya itu negatif, tetapi namanya juga menyesatkan. Ini TIDAK mengevaluasi ekspresi. Seharusnya disebut parse_to_expr atau sesuatu yang lain untuk menunjukkan bahwa pengguna akan tahu bahwa itu dimaksudkan untuk argumen karakter.
string
? Jawaban Martin Mächler patut mendapat lebih banyak dukungan.eval(parse(text = *))
solusi palsu.QQ = c('11','12','13','21','22','23')
yaitu: QQ = c (..., 'ij', ..) dengan i, j yang bervariasi pada rentang yang mungkin berbeda dari yang dijalankan ke yang dijalankan. Untuk contoh ini dan yang serupa, saya dapat menulis skrip sebagaipaste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
, dan opsieval(parse(text=...))
menciptakan vektor QQ di lingkungan kerja sesuai skrip. Apa yang akan menjadi cara pengkode R yang tepat untuk melakukan ini, jika tidak dengan "text = ..."?Jawaban:
The
eval()
Fungsi mengevaluasi ekspresi, tetapi"5+5"
adalah sebuah string, bukan ekspresi. Gunakanparse()
dengantext=<string>
untuk mengubah string menjadi ekspresi:Panggilan
eval()
memanggil banyak perilaku, beberapa tidak segera jelas:Lihat juga tryCatch .
sumber
quote()
,bquote()
atau alat yang lebih canggih yang disediakan olehrlang
paket.rlang
tetapi yang paling dekat saya temukan adalahparse_expr
panggilanparse_exprs
yang pada gilirannya sama dengan menggunakanparse
dan membungkusnyaeval
yang tampaknya sama dengan yang dilakukan di sini. Saya tidak yakin apa keuntungan menggunakanrlang
.rlang
, Anda akan bekerja secara langsung dengan ekspresi, bukan string. Tidak perlu langkah parse. Ini memiliki dua keunggulan. 1. Manipulasi ekspresi akan selalu menghasilkan ekspresi yang valid. Manipulasi string hanya akan menghasilkan string yang valid. Anda tidak akan tahu apakah itu ekspresi yang valid hingga Anda menguraikannya. 2. Tidak ada yang setara dengansubstitute()
kelas fungsi di dunia string, yang sangat membatasi kemampuan Anda untuk memanipulasi panggilan fungsi. Pertimbangkan pembungkus glm ini . Seperti apa bentuk string yang setara?Anda dapat menggunakan
parse()
fungsi ini untuk mengubah karakter menjadi ekspresi. Anda perlu menentukan bahwa input adalah teks, karena parse mengharapkan file secara default:sumber
parse
! github.com/wch/r-source/…Maaf tapi saya tidak mengerti mengapa terlalu banyak orang berpikir string adalah sesuatu yang bisa dievaluasi. Anda harus mengubah pola pikir Anda, sungguh. Lupakan semua koneksi antara string di satu sisi dan ekspresi, panggilan, evaluasi di sisi lain.
Koneksi (mungkin) hanya melalui
parse(text = ....)
dan semua programmer R yang baik harus tahu bahwa ini jarang cara yang efisien atau aman untuk membangun ekspresi (atau panggilan). Sebaliknya mempelajari lebih lanjut tentangsubstitute()
,quote()
, dan mungkin kekuatan menggunakando.call(substitute, ......)
.Dec.2017: Ok, ini sebuah contoh (dalam komentar, tidak ada format yang bagus):
dan jika Anda mendapatkan lebih berpengalaman Anda akan belajar bahwa
q5
adalah"call"
sedangkane5
adalah"expression"
, dan bahkan yange5[[1]]
identik denganq5
:sumber
q5 <- quote(5+5)
atas adalah ekspresi (sebenarnya "panggilan")5+5
dan itu adalah objek R, tetapi bukan string. Anda dapat mengevaluasinya kapan saja. Lagi: menggunakan, kutipan (), pengganti (), ... alih-alih parse membuat panggilan atau ekspresi secara langsung dan lebih efisien daripada melalui parse (teks =.). Menggunakaneval()
baik-baik saja, menggunakanparse(text=*)
rentan terhadap kesalahan dan kadang-kadang cukup tidak efisien dibandingkan dengan panggilan konstruksi dan memanipulasi mereka .. @Nick S: Inieval(q5)
ataueval(e5)
dalam contoh yang sedang berjalaneval(.)
saja. Maksud saya adalah bahwa orang tidak boleh menggunakanparse(text=.)
melainkanquote(.)
dll, untuk membangun panggilan yang nantinya akaneval()
diedit.eval(quote())
memang berfungsi dalam beberapa kasus tetapi akan gagal untuk beberapa kasus di manaeval(parse())
akan bekerja dengan baik.Atau, Anda dapat menggunakan
evals
daripander
paket saya untuk menangkap output dan semua peringatan, kesalahan, dan pesan lainnya bersama dengan hasil mentah:sumber
evaluate::evaluate
dengan benar-benar mengembalikan objek hasil; yang membuat fungsi Anda cocok untuk digunakan menelepon melalui mclapply. Saya harap fitur itu tetap ada!rapport
paket kami , dan telah secara aktif dipertahankan sejak saat itu karena banyak digunakan dalam layanan rapporter.net kami selain beberapa proyek lain juga - jadi saya yakin itu akan tetap dipertahankan untuk sementara :) Saya senang Anda menemukan itu berguna, terima kasih atas tanggapan Anda.Saat ini Anda juga dapat menggunakan
lazy_eval
fungsi darilazyeval
paket.sumber
Demikian pula dengan menggunakan
rlang
:sumber
rlang
jawaban tetapi bagaimana jika ada keuntungan dari alternatif ini? Sebenarnya, pemeriksaan ketat terhadap kode yang digunakan menunjukkan bahwa sebenarnya menggunakaneval(parse(....))
yang ingin saya hindari.