Apakah ada cara untuk mendapatkan nama indeks daftar di fungsi lapply () saya?
n = names(mylist)
lapply(mylist, function(list.elem) { cat("What is the name of this list element?\n" })
Saya bertanya sebelumnya apakah mungkin untuk mempertahankan nama indeks di daftar kembali lapply () , tapi saya masih tidak tahu apakah ada cara mudah untuk mengambil setiap nama elemen di dalam fungsi kustom. Saya ingin menghindari memanggil nama-nama itu sendiri, saya lebih suka mendapatkan nama dalam parameter fungsi.
Jawaban:
Sayangnya,
lapply
hanya memberi Anda elemen vektor yang Anda lewati. Cara kerja yang biasa dilakukan adalah memberikannya nama atau indeks vektor, bukan vektor itu sendiri.Tetapi perhatikan bahwa Anda selalu dapat menyampaikan argumen tambahan ke fungsi, jadi berikut ini berfungsi:
Di sini saya menggunakan
lapply
lebih dari indeksx
, tetapi juga lulusx
dan namax
. Seperti yang Anda lihat, urutan argumen fungsi bisa berupa apa saja -lapply
akan melewati "elemen" (di sini indeks) ke argumen pertama yang tidak ditentukan di antara yang ekstra. Dalam hal ini, saya tentukany
dann
, jadi hanya ada yangi
tersisa ...Yang menghasilkan sebagai berikut:
UPDATE Contoh sederhana, hasil yang sama:
Di sini fungsinya menggunakan variabel "global"
x
dan mengekstrak nama-nama dalam setiap panggilan.sumber
y
alih-alihx
sehingga (mudah-mudahan) lebih jelas bahwa fungsi dapat memanggil argumen itu apa saja. Juga mengubah nilai vektor menjadi11,12,13
.Ini pada dasarnya menggunakan solusi yang sama seperti Tommy, tetapi dengan
Map()
, tidak perlu mengakses variabel global yang menyimpan nama-nama komponen daftar.Atau, jika Anda mau
mapply()
sumber
mapply()
, perhatikanSIMPLIFY
opsi, yang default ke true. Dalam kasus saya, itu membuat semuanya menjadi matriks besar ketika saya hanya ingin daftar sederhana berlaku. Mengaturnya keF
(di dalammapply()
) membuatnya berjalan seperti yang dimaksudkan.UPDATE untuk R versi 3.2
Penafian: ini adalah trik hacky, dan mungkin berhenti bekerja di rilis berikutnya.
Anda bisa mendapatkan indeks menggunakan ini:
Catatan:
[]
diperlukan untuk ini untuk bekerja, karena itu menipu R untuk berpikir bahwa simboli
(yang berada dalam kerangka evaluasilapply
) dapat memiliki lebih banyak referensi, sehingga mengaktifkan duplikasi malas itu. Tanpa itu, R tidak akan menyimpan salinan terpisah darii
:Trik eksotis lainnya dapat digunakan, seperti
function(x){parent.frame()$i+0}
ataufunction(x){--parent.frame()$i}
.Dampak Kinerja
Apakah duplikasi paksa menyebabkan kehilangan kinerja? Iya! inilah tolok ukurnya:
Kesimpulan
Jawaban ini hanya menunjukkan bahwa Anda TIDAK boleh menggunakan ini ... Tidak hanya kode Anda akan lebih mudah dibaca jika Anda menemukan solusi lain seperti Tommy di atas, dan lebih kompatibel dengan rilis mendatang, Anda juga berisiko kehilangan optimisasi yang tim inti telah bekerja keras untuk melakukannya. mengembangkan!
Trik versi lama, tidak lagi berfungsi:
Hasil:
Penjelasan:
lapply
membuat panggilan formulirFUN(X[[1L]], ...)
,FUN(X[[2L]], ...)
dll. Jadi argumen yang dilewatinya adalah diX[[i]]
manai
indeks saat ini dalam loop. Jika kita mendapatkan ini sebelum dievaluasi (yaitu, jika kita menggunakansubstitute
), kita mendapatkan ekspresi yang tidak dievaluasiX[[i]]
. Ini adalah panggilan untuk[[
berfungsi, dengan argumenX
(simbol) dani
(bilangan bulat). Jadisubstitute(x)[[3]]
mengembalikan integer ini dengan tepat.Memiliki indeks, Anda dapat mengakses nama-nama sepele, jika Anda menyimpannya terlebih dahulu seperti ini:
Hasil:
Atau gunakan trik kedua ini: :-)
(hasilnya sama).
Penjelasan 2:
sys.call(1)
kembalilapply(...)
, jadi itulahsys.call(1)[[2]]
ekspresi yang digunakan sebagai argumen daftarlapply
. Melewati ini untukeval
menciptakan objek yang sah itunames
dapat mengakses. Tricky, tetapi berhasil.Bonus: cara kedua untuk mendapatkan nama:
Perhatikan bahwa itu
X
adalah objek yang valid dalam kerangka induk dariFUN
, dan referensi argumen daftarlapply
, sehingga kita bisa mendapatkannyaeval.parent
.sumber
lapply(list(a=10,b=10,c=10), function(x)substitute(x)[[3]])
mengembalikan semua menjadi 3. Apakah Anda akan menjelaskan bagaimana 3 ini dipilih? dan alasan perbedaannya? Apakah sama dengan panjang daftar, dalam hal ini, 3. Maaf jika ini adalah pertanyaan dasar tetapi ingin tahu bagaimana menerapkan ini dalam kasus umum.lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])
bekerja ... Aku akan memeriksa apa yang terjadi.lapply(list(a=10,b=10,c=10), function(x)eval.parent(quote(names(X)))[substitute(x)[[3]]])
tidak lagi berfungsi, dan memberikan kesalahan,Error in eval.parent(quote(names(X)))[substitute(x)[[3]]] : invalid subscript type 'symbol'
apakah ada cara mudah untuk memperbaikinya?Saya sering mengalami masalah yang sama ... Saya mulai menggunakan cara lain ... Daripada menggunakan
lapply
, saya sudah mulai menggunakanmapply
sumber
Anda dapat mencoba menggunakan
imap()
daripurrr
paket.Dari dokumentasi:
Jadi, Anda bisa menggunakannya seperti itu:
Yang akan memberi Anda hasil berikut:
sumber
Ulangi saja namanya.
sumber
mylist
di dalam fungsi. Lebih baik lagifunction(mylist, nm) ...
Jawaban Tommy berlaku untuk vektor bernama tetapi saya mendapat ide Anda tertarik pada daftar. Dan sepertinya dia melakukan end-around karena dia merujuk "x" dari lingkungan panggilan. Fungsi ini hanya menggunakan parameter yang diteruskan ke fungsi dan karenanya tidak membuat asumsi tentang nama objek yang diteruskan:
sumber
NULL
?! Jadilapply(x, function(x) NULL)
berikan jawaban yang sama ...lapply
selalu menambahkan nama darix
pada hasil sesudahnya .Jawaban saya berjalan ke arah yang sama dengan Tommy dan caracals, tetapi menghindari harus menyimpan daftar sebagai objek tambahan.
Hasil:
Ini memberikan daftar sebagai argumen bernama untuk MENYENANGKAN (bukan untuk menjilat). lapply hanya perlu beralih pada elemen-elemen dari daftar (hati-hati untuk mengubah argumen pertama ini menjadi lapply ketika mengubah panjang daftar).
Catatan: Memberikan daftar secara langsung ke lapply sebagai argumen tambahan juga berfungsi:
sumber
@Caracals dan @Tommy adalah solusi yang baik dan ini adalah contoh termasuk
list
´s dandata.frame
´s.r
adalah alist
darilist
´s dandata.frame
´s (dput(r[[1]]
pada akhirnya).Tujuannya adalah untuk
unlist
semua daftar, menempatkan urutanlist
nama ’sebagai kolom untuk mengidentifikasi kasus.Batalkan daftar tetapi bukan
data.frame
´s.Map
menempatkan urutan nama sebagai kolom.Reduce
bergabunglah dengan semuadata.frame
.PS
r[[1]]
:sumber
Katakanlah kita ingin menghitung panjang setiap elemen.
Jika tujuannya hanya untuk memberi label elemen yang dihasilkan, maka
lapply(mylist,length)
atau di bawah berfungsi.Jika tujuannya adalah untuk menggunakan label di dalam fungsi, maka
mapply()
berguna dengan mengulang dua objek; elemen daftar dan nama daftar.sumber
@ ferdinand-kraft memberi kami trik hebat dan kemudian memberi tahu kami bahwa kami tidak boleh menggunakannya karena tidak berdokumen dan karena overhead kinerja.
Saya tidak bisa berdebat banyak dengan poin pertama tetapi saya ingin mencatat bahwa overhead seharusnya jarang menjadi perhatian.
mari kita mendefinisikan fungsi aktif sehingga kita tidak perlu memanggil ekspresi kompleks
parent.frame()$i[]
tetapi hanya.i()
, Kami juga akan membuat.n()
untuk mengakses nama, yang seharusnya berfungsi untuk fungsionalitas dasar dan purrr (dan mungkin sebagian besar lainnya juga).Sekarang mari kita benchmark fungsi sederhana yang menempel item dari vektor ke indeks mereka, menggunakan pendekatan yang berbeda (operasi ini tentu saja dapat di-vectorized menggunakan
paste(vec, seq_along(vec))
tetapi bukan itu intinya di sini).Kami mendefinisikan fungsi benchmarking dan fungsi ploting dan plot hasilnya di bawah ini:
Dibuat pada 2019-11-15 oleh paket reprex (v0.3.0)
Penurunan pada awal grafik pertama adalah kebetulan, abaikan saja.
Kami melihat bahwa jawaban yang dipilih memang lebih cepat, dan untuk jumlah iterasi yang layak
.i()
solusi kami memang lebih lambat, overhead dibandingkan dengan jawaban yang dipilih adalah sekitar 3 kali overhead penggunaanpurrr::imap()
, dan jumlah sekitar, 25 ms untuk iterasi 30k, jadi saya kehilangan sekitar 1 ms per 1000 iterasi, 1 detik per juta. Itu sedikit biaya untuk kenyamanan menurut saya.sumber
Cukup tulis
lapply
fungsi kustom Anda sendiriKemudian gunakan seperti ini:
sumber