Saya ingin menetapkan beberapa variabel dalam satu baris di R. Apakah mungkin untuk melakukan sesuatu seperti ini?
values # initialize some vector of values
(a, b) = values[c(2,4)] # assign a and b to values at 2 and 4 indices of 'values'
Biasanya saya ingin menetapkan sekitar 5-6 variabel dalam satu baris, daripada memiliki banyak baris. Apakah ada alternatif lain?
list($a, $b) = array(1, 2)
? Itu akan menyenangkan! +1.vassign
saran saya di bawah hampir mendekati ... :)X <- list();X[c('a','b')] <- values[c(2,4)]
. Oke, Anda tidak menetapkannya di ruang kerja, tetapi simpan dengan baik di dalam daftar. Saya lebih suka melakukannya dengan cara itu.Jawaban:
Ada jawaban bagus di Blog Berjuang Melalui Masalah
Ini diambil dari sana, dengan sedikit modifikasi.
MENGGUNAKAN TIGA FUNGSI BERIKUT (Ditambah satu untuk memungkinkan daftar ukuran yang berbeda)
# Generic form '%=%' = function(l, r, ...) UseMethod('%=%') # Binary Operator '%=%.lbunch' = function(l, r, ...) { Envir = as.environment(-1) if (length(r) > length(l)) warning("RHS has more args than LHS. Only first", length(l), "used.") if (length(l) > length(r)) { warning("LHS has more args than RHS. RHS will be repeated.") r <- extendToMatch(r, l) } for (II in 1:length(l)) { do.call('<-', list(l[[II]], r[[II]]), envir=Envir) } } # Used if LHS is larger than RHS extendToMatch <- function(source, destin) { s <- length(source) d <- length(destin) # Assume that destin is a length when it is a single number and source is not if(d==1 && s>1 && !is.null(as.numeric(destin))) d <- destin dif <- d - s if (dif > 0) { source <- rep(source, ceiling(d/s))[1:d] } return (source) } # Grouping the left hand side g = function(...) { List = as.list(substitute(list(...)))[-1L] class(List) = 'lbunch' return(List) }
Kemudian untuk mengeksekusi:
Kelompokkan sisi kiri menggunakan fungsi baru
g()
Sisi kanan harus berupa vektor atau daftar Gunakan operator biner yang baru dibuat%=%
# Example Call; Note the use of g() AND `%=%` # Right-hand side can be a list or vector g(a, b, c) %=% list("hello", 123, list("apples, oranges")) g(d, e, f) %=% 101:103 # Results: > a [1] "hello" > b [1] 123 > c [[1]] [1] "apples, oranges" > d [1] 101 > e [1] 102 > f [1] 103
Contoh menggunakan daftar dengan ukuran berbeda:
Sisi Kiri Lebih Panjang
g(x, y, z) %=% list("first", "second") # Warning message: # In `%=%.lbunch`(g(x, y, z), list("first", "second")) : # LHS has more args than RHS. RHS will be repeated. > x [1] "first" > y [1] "second" > z [1] "first"
Sisi Kanan Lebih Panjang
g(j, k) %=% list("first", "second", "third") # Warning message: # In `%=%.lbunch`(g(j, k), list("first", "second", "third")) : # RHS has more args than LHS. Only first2used. > j [1] "first" > k [1] "second"
sumber
Pertimbangkan untuk menggunakan fungsionalitas yang termasuk dalam basis R.
Misalnya, buat 1 baris dataframe (katakanlah
V
) dan inisialisasi variabel Anda di dalamnya. Sekarang Anda dapat menetapkan ke beberapa variabel sekaligusV[,c("a", "b")] <- values[c(2, 4)]
, memanggil masing-masing dengan name (V$a
), atau menggunakan banyak di antaranya pada saat yang sama (values[c(5, 6)] <- V[,c("a", "b")]
).Jika Anda malas dan tidak ingin berkeliling memanggil variabel dari dataframe, Anda bisa
attach(V)
(meskipun saya pribadi tidak pernah melakukannya).# Initialize values values <- 1:100 # V for variables V <- data.frame(a=NA, b=NA, c=NA, d=NA, e=NA) # Assign elements from a vector V[, c("a", "b", "e")] = values[c(2,4, 8)] # Also other class V[, "d"] <- "R" # Use your variables V$a V$b V$c # OOps, NA V$d V$e
sumber
Saya mengumpulkan zeallot paket R untuk mengatasi masalah ini. zeallot menyertakan operator (
%<-%
) untuk tugas membongkar, menggandakan , dan merusak. LHS ekspresi penetapan dibuat menggunakan panggilan kec()
. RHS ekspresi tugas dapat berupa ekspresi apa pun yang mengembalikan atau merupakan vektor, daftar, daftar bersarang, bingkai data, string karakter, objek tanggal, atau objek khusus (dengan asumsi adadestructure
implementasi).Berikut adalah pertanyaan awal yang dikerjakan ulang menggunakan zeallot (versi terbaru, 0.0.5).
library(zeallot) values <- c(1, 2, 3, 4) # initialize a vector of values c(a, b) %<-% values[c(2, 4)] # assign `a` and `b` a #[1] 2 b #[1] 4
Untuk contoh dan informasi lebih lanjut, seseorang dapat melihat sketsa paket .
sumber
ini ide saya. Mungkin sintaksnya cukup sederhana:
`%tin%` <- function(x, y) { mapply(assign, as.character(substitute(x)[-1]), y, MoreArgs = list(envir = parent.frame())) invisible() } c(a, b) %tin% c(1, 2)
memberi seperti ini:
> a Error: object 'a' not found > b Error: object 'b' not found > c(a, b) %tin% c(1, 2) > a [1] 1 > b [1] 2
ini tidak diuji dengan baik.
sumber
c(c, d) %tin% c(1, 2) + 3
(=> c = 1, d = 1, mengembalikan numerik ( 0)) mungkin dianggap mengejutkan.assign
Opsi yang berpotensi berbahaya (sebanyak penggunaan itu berisiko) adalahVectorize
assign
:assignVec <- Vectorize("assign",c("x","value")) #.GlobalEnv is probably not what one wants in general; see below. assignVec(c('a','b'),c(0,4),envir = .GlobalEnv) a b 0 4 > b [1] 4 > a [1] 0
Atau saya kira Anda bisa memvektorisasi sendiri secara manual dengan fungsi Anda sendiri menggunakan
mapply
yang mungkin menggunakan default yang masuk akal untukenvir
argumen. Misalnya,Vectorize
akan mengembalikan fungsi dengan properti lingkungan yang samaassign
, yang dalam hal ini adalahnamespace:base
, atau Anda bisa menyetelnyaenvir = parent.env(environment(assignVec))
.sumber
Seperti yang dijelaskan orang lain, sepertinya tidak ada bawaan apa pun. ... tetapi Anda dapat mendesain
vassign
fungsi sebagai berikut:vassign <- function(..., values, envir=parent.frame()) { vars <- as.character(substitute(...())) values <- rep(values, length.out=length(vars)) for(i in seq_along(vars)) { assign(vars[[i]], values[[i]], envir) } } # Then test it vals <- 11:14 vassign(aa,bb,cc,dd, values=vals) cc # 13
Satu hal yang perlu dipertimbangkan adalah bagaimana menangani kasus di mana Anda misalnya menentukan 3 variabel dan 5 nilai atau sebaliknya. Di sini saya hanya mengulangi (atau memotong) nilai-nilai menjadi sama panjangnya dengan variabel. Mungkin peringatan akan lebih bijaksana. Tapi itu memungkinkan yang berikut:
vassign(aa,bb,cc,dd, values=0) cc # 0
sumber
...()
, mana yang tampak seperti ilmu hitam bagi saya ...?...()
itu sihir hitam yang ekstrim ;-). Kebetulan ketika "panggilan fungsi"...()
diganti, itu menjadi daftar pasangan yang dapat diteruskan keas.character
dan voila, Anda mendapat argumen sebagai string ...envir=parent.frame()
- Dan Anda dapat menentukan misalnyaenvir=globalenv()
jika Anda mau.`vassign<-` <- function (..., envir = parent.frame (), value)
dan seterusnya. Namun, tampaknya objek pertama yang ditugaskan harus sudah ada. Ada ide?list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)
Melayani tujuan saya, yaitu, menugaskan lima 2s menjadi lima huruf pertama.
sumber
https://stat.ethz.ch/R-manual/R-devel/library/base/html/list2env.html :
list2env( list( a=1, b=2:4, c=rpois(10,10), d=gl(3,4,LETTERS[9:11]) ), envir=.GlobalEnv )
sumber
Punya masalah serupa baru-baru ini dan inilah percobaan saya menggunakan
purrr::walk2
purrr::walk2(letters,1:26,assign,envir =parent.frame())
sumber
Jika satu-satunya persyaratan Anda adalah memiliki satu baris kode, lalu bagaimana dengan:
> a<-values[2]; b<-values[4]
sumber
Saya khawatir solusi elegan yang Anda cari (seperti
c(a, b) = c(2, 4)
) sayangnya tidak ada. Tapi jangan menyerah, saya tidak yakin! Solusi terdekat yang dapat saya pikirkan adalah yang ini:attach(data.frame(a = 2, b = 4))
atau jika Anda terganggu dengan peringatan, matikan:
attach(data.frame(a = 2, b = 4), warn = F)
Tetapi saya kira Anda tidak puas dengan solusi ini, saya juga tidak akan ...
sumber
R> values = c(1,2,3,4) R> a <- values[2]; b <- values[3]; c <- values[4] R> a [1] 2 R> b [1] 3 R> c [1] 4
sumber
Versi lain dengan rekursi:
let <- function(..., env = parent.frame()) { f <- function(x, ..., i = 1) { if(is.null(substitute(...))){ if(length(x) == 1) x <- rep(x, i - 1); stopifnot(length(x) == i - 1) return(x); } val <- f(..., i = i + 1); assign(deparse(substitute(x)), val[[i]], env = env); return(val) } f(...) }
contoh:
> let(a, b, 4:10) [1] 4 5 6 7 8 9 10 > a [1] 4 > b [1] 5 > let(c, d, e, f, c(4, 3, 2, 1)) [1] 4 3 2 1 > c [1] 4 > f [1] 1
Versi saya:
let <- function(x, value) { mapply( assign, as.character(substitute(x)[-1]), value, MoreArgs = list(envir = parent.frame())) invisible() }
contoh:
> let(c(x, y), 1:2 + 3) > x [1] 4 > y [1]
sumber
Menggabungkan beberapa jawaban yang diberikan di sini + sedikit garam, bagaimana dengan solusi ini:
assignVec <- Vectorize("assign", c("x", "value")) `%<<-%` <- function(x, value) invisible(assignVec(x, value, envir = .GlobalEnv)) c("a", "b") %<<-% c(2, 4) a ## [1] 2 b ## [1] 4
Saya menggunakan ini untuk menambahkan bagian R di sini: http://rosettacode.org/wiki/Sort_three_variables#R
Peringatan: Ini hanya berfungsi untuk menetapkan variabel global (seperti
<<-
). Jika ada solusi yang lebih baik dan lebih umum, mohon. beri tahu saya di komentar.sumber