Jika saya memiliki beberapa daftar R mylist
, Anda dapat menambahkan item obj
ke dalamnya seperti:
mylist[[length(mylist)+1]] <- obj
Tapi pasti ada beberapa cara yang lebih kompak. Ketika saya masih baru di R, saya mencoba menulis lappend()
seperti:
lappend <- function(lst, obj) {
lst[[length(lst)+1]] <- obj
return(lst)
}
tetapi tentu saja itu tidak berhasil karena semantik panggilan-dengan-nama R ( lst
secara efektif disalin atas panggilan, sehingga perubahan lst
tidak terlihat di luar lingkup lappend()
. Saya tahu Anda dapat melakukan peretasan lingkungan dalam fungsi R untuk menjangkau di luar ruang lingkup fungsi Anda dan mutasi lingkungan panggilan, tetapi sepertinya palu besar untuk menulis fungsi penambahan sederhana.
Adakah yang bisa menyarankan cara yang lebih indah untuk melakukan ini? Poin bonus jika berfungsi untuk vektor dan daftar.
Jawaban:
Jika daftar string, gunakan saja
c()
fungsinya:Itu bekerja pada vektor juga, jadi apakah saya mendapatkan poin bonus?
Sunting (2015-Feb-01): Posting ini akan muncul pada ulang tahun kelima. Beberapa pembaca yang baik terus mengulangi kekurangannya, jadi tentu saja lihat juga komentar di bawah ini. Satu saran untuk
list
jenis:Secara umum, tipe R membuatnya sulit untuk memiliki satu dan hanya satu idiom untuk semua jenis dan kegunaan.
sumber
LL
pasti masih memiliki dua elemen setelahC(LL, c="harry")
dipanggil.LL <- c(LL, c="harry")
.c()
memiliki 2 argumen: daftar yang saya coba tambahkan, yaitulist(a=3, b=c(4, 5))
, dan item yang saya coba tambahkan, yaituc=c(6, 7)
. Jika Anda menggunakan pendekatan saya, Anda akan melihat bahwa 2 item daftar ditambahkan (6
dan7
, dengan namac1
danc2
) alih-alih vektor 2-elemen tunggal bernamac
sebagaimana dimaksudkan dengan jelas!mylist <- list(mylist, list(obj))
? Jika ya akan menyenangkan untuk memodifikasi jawabannyaOP (dalam revisi pertanyaan yang diperbarui pada bulan April 2012) tertarik untuk mengetahui apakah ada cara untuk menambah daftar dalam waktu konstan yang diamortisasi, seperti yang dapat dilakukan, misalnya, dengan wadah C ++
vector<>
. Jawaban terbaik (s?) Di sini sejauh ini hanya menunjukkan waktu eksekusi relatif untuk berbagai solusi mengingat masalah ukuran tetap, tetapi tidak membahas salah satu efisiensi algoritmik berbagai solusi secara langsung. Komentar di bawah ini banyak dari jawaban yang membahas efisiensi algoritmik dari beberapa solusi, tetapi dalam setiap kasus hingga saat ini (per April 2015) mereka sampai pada kesimpulan yang salah.Efisiensi algoritmik menangkap karakteristik pertumbuhan, baik dalam waktu (waktu eksekusi) atau ruang (jumlah memori yang dikonsumsi) ketika ukuran masalah bertambah . Menjalankan tes kinerja untuk berbagai solusi mengingat masalah ukuran tetap tidak membahas tingkat pertumbuhan berbagai solusi. OP tertarik untuk mengetahui apakah ada cara untuk menambahkan objek ke daftar R dalam "waktu konstan diamortisasi". Apa artinya? Untuk menjelaskan, pertama izinkan saya menggambarkan "waktu konstan":
Pertumbuhan konstan atau O (1) :
Jika waktu yang diperlukan untuk melakukan tugas yang diberikan tetap sama dengan ukuran masalah yang berlipat ganda , maka kita katakan algoritma menunjukkan pertumbuhan waktu yang konstan , atau dinyatakan dalam notasi "O Besar", menunjukkan O (1) pertumbuhan waktu. Ketika OP mengatakan "diamortisasi" waktu konstan, ia hanya berarti "dalam jangka panjang" ... yaitu, jika melakukan satu operasi kadang-kadang membutuhkan waktu lebih lama dari biasanya (misalnya jika buffer yang dialokasikan sebelumnya habis dan kadang-kadang membutuhkan pengubahan ukuran ke yang lebih besar). ukuran buffer), selama kinerja rata-rata jangka panjang adalah waktu yang konstan, kita masih akan menyebutnya O (1).
Sebagai perbandingan, saya juga akan menjelaskan "waktu linear" dan "waktu kuadratik":
Pertumbuhan linier atau O (n) :
Jika waktu yang dibutuhkan untuk melakukan tugas yang diberikan berlipat ganda ketika ukuran masalahnya berlipat ganda , maka kita katakan algoritma menunjukkan waktu linier , atau pertumbuhan O (n) .
Pertumbuhan kuadratik atau O (n 2 ) :
Jika waktu yang dibutuhkan untuk melakukan tugas yang diberikan meningkat dengan kuadrat dari ukuran masalah , mereka kita katakan algoritma menunjukkan waktu kuadratik , atau O (n 2 ) pertumbuhan.
Ada banyak kelas efisiensi algoritma lainnya; Saya tunduk pada artikel Wikipedia untuk diskusi lebih lanjut.
Saya berterima kasih kepada @CronAcronis atas jawabannya, karena saya baru di R dan senang memiliki blok kode yang dibuat untuk melakukan analisis kinerja dari berbagai solusi yang disajikan pada halaman ini. Saya meminjam kode untuk analisis saya, yang saya duplikat (dibungkus dengan fungsi) di bawah:
Hasil yang diposting oleh @CronAcronis tampaknya menyarankan bahwa
a <- list(a, list(i))
metode ini tercepat, setidaknya untuk ukuran masalah 10.000, tetapi hasil untuk ukuran masalah tunggal tidak mengatasi pertumbuhan solusi. Untuk itu, kita perlu menjalankan minimal dua tes profil, dengan ukuran masalah yang berbeda:Pertama-tama, sebuah kata tentang nilai min / lq / mean / median / uq / max: Karena kita melakukan tugas yang sama persis untuk masing-masing 5 run, di dunia yang ideal, kita dapat berharap bahwa itu akan mengambil persis sama persis jumlah waktu untuk setiap lari. Tetapi proses pertama biasanya bias terhadap waktu yang lebih lama karena fakta bahwa kode yang kami uji belum dimuat ke dalam cache CPU. Setelah menjalankan pertama kali, kami berharap waktu akan cukup konsisten, tetapi kadang-kadang kode kami dapat diusir dari cache karena gangguan centang timer atau gangguan perangkat keras lain yang tidak terkait dengan kode yang kami uji. Dengan menguji cuplikan kode 5 kali, kami mengizinkan kode untuk dimuat ke dalam cache selama proses pertama dan kemudian memberikan masing-masing 4 cuplikan peluang untuk berjalan hingga selesai tanpa gangguan dari peristiwa luar. Untuk alasan ini,
Perhatikan bahwa saya memilih untuk pertama kali menjalankan dengan ukuran masalah 2000 dan kemudian 20000, jadi ukuran masalah saya meningkat dengan faktor 10 dari menjalankan pertama ke yang kedua.
Performa
list
solusi: O (1) (waktu konstan)Pertama-tama mari kita lihat pertumbuhan
list
solusi, karena kita dapat segera mengetahui bahwa ini adalah solusi tercepat di kedua proses pembuatan profil: Pada proses pertama, dibutuhkan 854 detik mikro (0,854 mili detik) untuk melakukan 2.000 tugas "menambahkan" tugas. Pada putaran kedua, dibutuhkan 8,746 milidetik untuk melakukan 20.000 tugas "tambahkan". Seorang pengamat yang naif akan berkata, "Ah,list
solusinya menunjukkan pertumbuhan O (n), karena ketika ukuran masalah bertambah sepuluh kali lipat, begitu pula waktu yang diperlukan untuk melaksanakan tes." Masalah dengan analisis itu adalah bahwa apa yang diinginkan OP adalah tingkat pertumbuhan dari penyisipan objek tunggal , bukan tingkat pertumbuhan dari keseluruhan masalah. Mengetahui itu, maka jelas bahwa itulist
solusi memberikan persis apa yang diinginkan OP: metode menambahkan objek ke daftar dalam waktu O (1).Kinerja solusi lain
Tidak ada solusi lain yang mendekati kecepatan dari
list
solusi tersebut, tetapi bagaimanapun, informatif untuk memeriksanya:Sebagian besar solusi lain tampaknya O (n) dalam kinerja. Misalnya,
by_index
solusinya, solusi yang sangat populer berdasarkan frekuensi yang saya temukan di pos SO lainnya, membutuhkan 11,6 milidetik untuk menambahkan 2000 objek, dan 953 milidetik untuk menambahkan sepuluh kali lebih banyak objek. Waktu masalah secara keseluruhan tumbuh dengan faktor 100, sehingga pengamat yang naif mungkin mengatakan "Ah,by_index
solusinya menunjukkan pertumbuhan O (n 2 ), karena ketika ukuran masalah tumbuh dengan faktor sepuluh, waktu yang dibutuhkan untuk melaksanakan tes tumbuh dengan faktor 100. "Seperti sebelumnya, analisis ini cacat, karena OP tertarik pada pertumbuhan penyisipan objek tunggal. Jika kita membagi pertumbuhan waktu keseluruhan dengan pertumbuhan ukuran masalah, kita menemukan bahwa pertumbuhan waktu objek penambahan meningkat dengan faktor hanya 10, bukan faktor 100, yang cocok dengan pertumbuhan ukuran masalah, jadiby_index
solusinya adalah O (n). Tidak ada solusi yang menunjukkan pertumbuhan O (n 2 ) untuk menambahkan objek tunggal.sumber
Dalam jawaban lain, hanya
list
pendekatan yang menghasilkan O (1) menambahkan, tetapi menghasilkan struktur daftar yang sangat bersarang, dan bukan daftar tunggal. Saya telah menggunakan struktur data di bawah ini, mereka mendukung O (1) (diamortisasi) ditambahkan, dan memungkinkan hasilnya dikonversi kembali ke daftar biasa.dan
Gunakan mereka sebagai berikut:
Solusi ini dapat diperluas menjadi objek penuh yang mendukung operasi yang terkait dengan daftar sendiri, tetapi itu akan tetap sebagai latihan bagi pembaca.
Varian lain untuk daftar bernama:
Tolak ukur
Perbandingan kinerja menggunakan kode @ phonetagger (yang didasarkan pada kode @Cron Arconis). Saya juga menambahkan
better_env_as_container
dan mengubahenv_as_container_
sedikit. Dokumen aslienv_as_container_
rusak dan tidak benar-benar menyimpan semua angka.hasil:
Saya telah menambahkan
linkedList
danexpandingList
dan versi keduanya. IniinlinedLinkedList
pada dasarnya adalah salinanlist_
, tetapi juga mengubah struktur bersarang kembali menjadi daftar polos. Di luar itu perbedaan antara versi inline dan non-inline adalah karena overhead panggilan fungsi.Semua varian
expandingList
danlinkedList
menunjukkan kinerja penambahan O (1), dengan penskalaan waktu penskalaan linear dengan jumlah item yang ditambahkan.linkedList
lebih lambat daripadaexpandingList
, dan overhead panggilan fungsi juga terlihat. Jadi, jika Anda benar-benar membutuhkan semua kecepatan yang bisa Anda dapatkan (dan ingin tetap menggunakan kode R), gunakan versi inline dariexpandingList
.Saya juga sudah melihat implementasi C dari R, dan kedua pendekatan harus O (1) tambahkan untuk ukuran apa pun sampai Anda kehabisan memori.
Saya juga telah mengubah
env_as_container_
, versi asli akan menyimpan setiap item di bawah indeks "i", menimpa item yang ditambahkan sebelumnya. Thebetter_env_as_container
Saya telah menambahkan sangat mirip denganenv_as_container_
tapi tanpadeparse
barang-barang. Keduanya menunjukkan kinerja O (1), tetapi mereka memiliki overhead yang sedikit lebih besar dari daftar yang ditautkan / diperluas.Memori di atas kepala
Dalam implementasi CR ada overhead 4 kata dan 2 int per objek yang dialokasikan. The
linkedList
pendekatan mengalokasikan satu daftar panjang dua per append, untuk total (4 * 8 + 4 + 4 + 2 * 8 =) 56 bytes per item ditambahkan pada 64-bit komputer (termasuk alokasi memori di atas kepala, jadi mungkin lebih dekat ke 64 byte). TheexpandingList
Pendekatan menggunakan satu kata per item ditambahkan, ditambah salinan ketika dua kali lipat panjang vektor, sehingga penggunaan memori total hingga 16 byte per item. Karena memori semua dalam satu atau dua objek, overhead per objek tidak signifikan. Saya belum melihat ke dalamenv
penggunaan memori, tapi saya pikir akan lebih dekatlinkedList
.sumber
list_
pilihan adalah lebih cepat dan dapat berguna jika Anda tidak perlu mengkonversi ke daftar normal, yaitu jika Anda menggunakan hasilnya sebagai stack.environment
hal - hal yang saya gunakan untuk nestoR.) Kemacetan saya hampir selalu menghabiskan waktu manusia coding dan melakukan analisis data, tapi saya menghargai tolok ukur yang saya temukan pada posting ini. Adapun overhead memori, saya tidak keberatan hingga sekitar satu kB per node untuk aplikasi saya. Saya berpegang pada array besar, dll.Di Lisp kami melakukannya dengan cara ini:
meskipun itu 'kontra', bukan hanya 'c'. Jika Anda perlu memulai dengan daftar kosong, gunakan l <- NULL.
sumber
c()
salinan fungsi argumen menjadi vektor / daftar baru dan kembali itu.Anda menginginkan sesuatu seperti ini, mungkin?
Ini bukan fungsi yang sangat sopan (menugaskan
parent.frame()
agak kasar) tetapi IIUYC adalah apa yang Anda minta.sumber
Saya telah membuat perbandingan kecil metode yang disebutkan di sini.
Hasil:
sumber
list = list
bukan hanya pemenang - tetapi dengan 1 hingga 2 pesanan atau besarnya!Jika Anda meneruskan variabel daftar sebagai string yang dikutip, Anda dapat mencapainya dari dalam fungsi seperti:
begitu:
atau untuk kredit tambahan:
sumber
Tidak yakin mengapa Anda tidak berpikir metode pertama Anda tidak akan berhasil. Anda memiliki bug dalam fungsi lappend: length (daftar) harus length (lst). Ini berfungsi dengan baik dan mengembalikan daftar dengan obj yang ditambahkan.
sumber
lappend()
yang saya berikan dan tampaknya berkinerja sebaik c () dan append (), yang semuanya menunjukkan perilaku O (n ^ 2).coba fungsi ini lappend
dan saran lain dari halaman ini. Tambahkan vektor bernama ke daftar
Sampai jumpa.
sumber
Saya pikir apa yang ingin Anda lakukan sebenarnya adalah lewat referensi (pointer) ke function-- buat lingkungan baru (yang diteruskan oleh referensi ke fungsi) dengan daftar ditambahkan ke dalamnya:
Sekarang Anda hanya mengubah daftar yang ada (tidak membuat yang baru)
sumber
Ini adalah cara mudah untuk menambahkan item ke Daftar R:
Atau secara terprogram:
sumber
append()
fungsi, tetapi ini benar-benar fungsi gabungan dan hanya bekerja pada vektor.append()
bekerja pada vektor dan daftar, dan itu adalah append yang benar (yang pada dasarnya sama dengan concatenate, jadi saya tidak melihat apa masalah Anda)sebenarnya ada subtelty dengan
c()
fungsi tersebut. Jika kamu melakukan:Anda akan mendapatkan seperti yang diharapkan:
tetapi jika Anda menambahkan matriks dengan
x <- c(x, matrix(5,2,2)
, daftar Anda akan memiliki 4 elemen nilai lainnya5
! Anda sebaiknya melakukan:Ini berfungsi untuk objek lain dan Anda akan mendapatkan seperti yang diharapkan:
Akhirnya, fungsi Anda menjadi:
dan itu bekerja untuk semua jenis objek. Anda bisa lebih pintar dan melakukan:
sumber
Ada juga
list.append
darirlist
( tautan ke dokumentasi )Ini sangat sederhana dan efisien.
sumber
c()
ataulist
-metode. Keduanya jauh lebih cepat.rlist::list.append()
, itu pada dasarnya pembungkusbase::c()
.Untuk validasi saya menjalankan kode benchmark yang disediakan oleh @Cron. Ada satu perbedaan utama (selain berjalan lebih cepat pada prosesor i7 yang lebih baru):
by_index
sekarang berkinerja hampir sama denganlist_
:Untuk referensi di sini adalah kode benchmark disalin secara verbatim dari jawaban @ Cron (kalau-kalau nanti dia mengubah konten):
sumber
sumber
Ini adalah pertanyaan yang sangat menarik dan saya harap pemikiran saya di bawah ini dapat memberikan kontribusi solusi untuk itu. Metode ini memang memberikan daftar datar tanpa pengindeksan, tetapi memang memiliki daftar dan tidak terdaftar untuk menghindari struktur bersarang. Saya tidak yakin tentang kecepatan karena saya tidak tahu bagaimana melakukan benchmark.
sumber
mylist<-list(1,2,3) mylist<-c(mylist,list(5))
Jadi kita dapat dengan mudah menambahkan elemen / objek menggunakan kode di atas
sumber