LHS पर एक ही पंक्ति में कई नए चर असाइन करें


89

मैं आर में एक ही पंक्ति में कई चर असाइन करना चाहता हूं। क्या ऐसा कुछ करना संभव है?

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'

आमतौर पर मैं कई लाइनों के बजाय एक लाइन में लगभग 5-6 चर असाइन करना चाहता हूं। क्या कोई विकल्प है?


आप PHP में कुछ की तरह मतलब है list($a, $b) = array(1, 2)? वह अच्छा रहेगा! +1।
टीएमएस

@ टॉमस टी - मुझे लगता है कि मेरा vassignसुझाव नीचे दिया गया है ... :)
टॉमी

ध्यान दें: इस बिट आर के लिए अर्धविराम की आवश्यकता नहीं है
Iterator

1
यदि आप इसे एक उपयुक्त वातावरण में आज़माएँगे, तो यह उतना ही आसान होगा X <- list();X[c('a','b')] <- values[c(2,4)]। ठीक है, आप उन्हें कार्यक्षेत्र में असाइन नहीं करते हैं, लेकिन उन्हें एक सूची में एक साथ रखते हैं। मैं इसे इस तरह से करना पसंद करूंगा।
जोरिस Meys

7
मुझे अजगर पसंद है, बस ए, बी = 1,2। नीचे दिए गए सभी उत्तर 100x कठिन हैं
AppleLover

जवाबों:


39

स्ट्रैसबलिंग थ्रू प्रॉब्लम्स ब्लॉग पर एक बेहतरीन जवाब है

यह वहाँ से लिया गया है, बहुत मामूली संशोधनों के साथ।

पूरे तीन चरणों का उपयोग (प्लस विभिन्न आकारों की सूची के लिए अनुमति देने के लिए एक)

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


फिर निष्पादित करने के लिए:

नए फ़ंक्शन g() का उपयोग करके बाएं हाथ की ओर समूह बनाएं दाहिने हाथ की तरफ एक वेक्टर या एक सूची होनी चाहिए नव-निर्मित बाइनरी ऑपरेटर का उपयोग करें%=%

# 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


विभिन्न आकारों की सूची का उपयोग करके उदाहरण:

लंबे समय तक बाएं हाथ की ओर

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"

लम्बे दाहिने हाथ की ओर

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"

34

मैं एक बहुत ही समस्या से निपटने के लिए एक आर पैकेज zeallot एक साथ रखा । zeallot में अनपैकिंग %<-%, मल्टीपल, और डिस्ट्रक्टिंग असाइनमेंट के लिए एक ऑपरेटर ( ) शामिल है । असाइनमेंट एक्सप्रेशन का LHS कॉल का उपयोग करके बनाया गया है c()। असाइनमेंट अभिव्यक्ति का आरएचएस कोई भी अभिव्यक्ति हो सकता है जो रिटर्न या वेक्टर, सूची, नेस्टेड सूची, डेटा फ़्रेम, चरित्र स्ट्रिंग, दिनांक ऑब्जेक्ट, या कस्टम ऑब्जेक्ट्स (यह मानते हुए कि एक destructureकार्यान्वयन है) हो सकता है।

यहाँ zeallot (नवीनतम संस्करण, 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

अधिक उदाहरणों और सूचनाओं के लिए कोई भी पैकेज विगनेट की जांच कर सकता है ।


यह वही है जो मैं खोजने की उम्मीद कर रहा था, कुछ ऐसा जो अजगर को वाक्यविन्यास के लिए सक्षम बनाता है, ओपी पूछ रहा था, एक आर पैकेज में लागू किया गया
jafelds

1
प्रत्येक चर नाम पर एक मैट्रिक्स असाइन करने के बारे में क्या?
स्टैटसॉरसस

33

बेस आर में शामिल कार्यक्षमता का उपयोग करने पर विचार करें।

उदाहरण के लिए, 1 पंक्ति डेटाफ़्रेम (कहना V) बनाएँ और इसमें अपने चर को इनिशियलाइज़ करें। अब आप एक ही बार में कई वेरिएबल्स को असाइन कर सकते हैं V[,c("a", "b")] <- values[c(2, 4)], प्रत्येक को एक नाम से बुला सकते हैं ( V$a), या एक ही समय में उनमें से कई का उपयोग कर सकते हैं ( values[c(5, 6)] <- V[,c("a", "b")])।

यदि आप आलसी हो जाते हैं और डेटाफ़्रेम से कॉलिंग वैरिएबल के आसपास नहीं जाना चाहते हैं, तो आप attach(V)(हालांकि मैं व्यक्तिगत रूप से ऐसा कभी नहीं करता)।

# 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

4
+10 अगर मैं कर सका। मुझे आश्चर्य है कि लोग इस तरह के स्पष्ट मामलों में सूचियों का उपयोग करने से इंकार करते हैं, बल्कि कार्यक्षेत्र को बहुत सारे अर्थहीन चरों से जोड़ते हैं। (आप सूचियों का उपयोग करते हैं, data.frame के रूप में एक विशेष प्रकार की सूची है। मैं सिर्फ एक और सामान्य का उपयोग
करूंगा

लेकिन आपके पास एक ही कॉलम में विभिन्न प्रकार के तत्व नहीं हो सकते हैं, और न ही आप अपने
डेटाफ्रेम के

1
दरअसल, आप सूची को एक डेटा फ्रेम में स्टोर कर सकते हैं - Google "सूची कॉलम"।

यह एक बुरा दृष्टिकोण नहीं है, इसमें कुछ उपयुक्तताएं हैं, लेकिन यह कल्पना करना भी मुश्किल नहीं है कि कई उपयोगकर्ता इस तरह से असाइन किए गए चर का उपयोग या उपयोग करने की कोशिश कर रहे थे, हर बार डेटा.फ्रेम सिंटैक्स से निपटना नहीं चाहेंगे।
ब्रैंडन

13

यहाँ मेरा विचार है संभवतः वाक्य रचना काफी सरल है:

`%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)

इस तरह देता है:

> 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

हालांकि यह अच्छी तरह से परीक्षण नहीं है।


2
Koshke, मुझे बहुत अच्छा लगता है :-) लेकिन मैं ऑपरेटर पूर्वता के बारे में थोड़ा चिंतित हूं:% कुछ% ऑपरेटर बहुत अधिक हैं, इसलिए उदाहरण c(c, d) %tin% c(1, 2) + 3(=> c = 1, d = 1, रिटर्न संख्यात्मक का व्यवहार ( ०)) आश्चर्य की बात मानी जा सकती है।
SX

10

एक संभावित खतरनाक (जितना उपयोग assignकरना उतना जोखिम भरा है) विकल्प निम्नलिखित होगा Vectorize 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

या मुझे लगता है कि आप इसे अपने स्वयं के फ़ंक्शन के साथ मैन्युअल रूप से वेक्टर कर सकते हैं mapplyकि शायद envirतर्क के लिए एक समझदार डिफ़ॉल्ट का उपयोग करता है । उदाहरण के लिए, Vectorizeउसी पर्यावरण गुण के साथ एक फ़ंक्शन लौटाएगा assign, जो इस मामले में है namespace:base, या आप बस सेट कर सकते हैं envir = parent.env(environment(assignVec))


8

जैसा कि अन्य लोगों ने समझाया, इसमें निर्मित कुछ भी प्रतीत नहीं होता है ... लेकिन आप एक vassignफंक्शन को इस प्रकार डिजाइन कर सकते हैं:

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

एक बात पर विचार करना है कि कैसे उन मामलों को संभालना है जहां आप उदाहरण के लिए 3 चर और 5 मान या अन्य तरीके निर्दिष्ट करते हैं। यहाँ मैं चर के रूप में एक ही लंबाई के मान को दोहराता हूं (या काटता हूं)। शायद एक चेतावनी विवेकपूर्ण होगी। लेकिन यह निम्नलिखित की अनुमति देता है:

vassign(aa,bb,cc,dd, values=0)
cc # 0

मुझे यह पसंद है, लेकिन मुझे चिंता होगी कि यह किसी ऐसे मामले में टूट सकता है जहां इसे एक फ़ंक्शन के भीतर से बुलाया गया था (हालांकि इस काम का एक सरल परीक्षण, मेरे हल्के आश्चर्य के लिए)। क्या आप समझा सकते हैं ...(), जो मुझे काला जादू लगता है ...?
बेन बोल्कर

1
@ बेन बोल्कर - हाँ, ...()अत्यधिक काला जादू है ;; ऐसा होता है कि जब "फ़ंक्शन कॉल" ...()को प्रतिस्थापित किया जाता है, तो यह एक पैरलिस्ट बन जाता है जिसे वॉयला किया जा सकता है as.character, आपको स्ट्रिंग्स के रूप में तर्क मिल गए ...
टॉमी

1
@Ben Bolker - और इसे किसी फ़ंक्शन के भीतर से कॉल करने के बाद भी सही ढंग से काम करना चाहिए क्योंकि यह उपयोग करता है envir=parent.frame()- और envir=globalenv()यदि आप चाहें तो आप इसे निर्दिष्ट कर सकते हैं।
टॉमी

यहां तक ​​कि कूलर इसे प्रतिस्थापन फ़ंक्शन के रूप में होगा: `vassign<-` <- function (..., envir = parent.frame (), value)और इसी तरह। हालाँकि, ऐसा लगता है कि सौंपी जाने वाली पहली वस्तु को पहले से मौजूद होना चाहिए। कोई विचार?
SX

@ कबीलेइट्स - हां, यह कूलर होगा लेकिन मुझे नहीं लगता कि आप उस सीमा के आसपास काम कर सकते हैं जिसका पहला तर्क मौजूद है - इसीलिए इसे प्रतिस्थापन कार्य कहा जाता है :) ... लेकिन मुझे पता है कि क्या आपको पता चलेगा !
टॉमी

6
list2env(setNames(as.list(rep(2,5)), letters[1:5]), .GlobalEnv)

पहले पांच अक्षरों में पाँच 2s निर्दिष्ट करते हुए, मेरे उद्देश्य को पूरा किया।



4

हाल ही में इसी तरह की समस्या थी और यहाँ मेरी कोशिश थी purrr::walk2

purrr::walk2(letters,1:26,assign,envir =parent.frame()) 

3

यदि आपकी एकमात्र आवश्यकता कोड की एक पंक्ति है, तो कैसे:

> a<-values[2]; b<-values[4]

2
एक
रसीले

मैं @ user236215 के समान नाव पर हूं। जब दाहिने हाथ की ओर एक सदिश लौटाने वाली एक जटिल अभिव्यक्ति होती है, तो दोहराए जाने वाला कोड बहुत गलत लगता है ...
Airstrike

1

मुझे डर है कि आप (जैसे c(a, b) = c(2, 4)) unfortunatelly के लिए देख रहे हैं कि ग्यारह समाधान मौजूद नहीं है। लेकिन हार मत मानो, मुझे यकीन नहीं है! निकटतम समाधान मैं सोच सकता हूं कि यह एक है:

attach(data.frame(a = 2, b = 4))

या यदि आप चेतावनी से परेशान हैं, तो उन्हें बंद करें:

attach(data.frame(a = 2, b = 4), warn = F)

लेकिन मुझे लगता है कि आप इस समाधान से संतुष्ट नहीं हैं, मैं भी नहीं होगा ...


1
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

0

पुनरावृत्ति के साथ एक और संस्करण:

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(...)
}

उदाहरण:

> 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

मेरा संस्करण:

let <- function(x, value) {
    mapply(
        assign,
        as.character(substitute(x)[-1]),
        value,
        MoreArgs = list(envir = parent.frame()))
    invisible()
}

उदाहरण:

> let(c(x, y), 1:2 + 3)
> x
[1] 4
> y
[1] 

0

यहाँ दिए गए कुछ उत्तरों को मिलाकर + थोड़ा सा नमक, इस समाधान के बारे में कैसे:

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

मैंने इसका उपयोग यहाँ R अनुभाग जोड़ने के लिए किया है: http://rosettacode.org/wiki/Sort_three_variables#R

कैविएट: यह केवल वैश्विक चर (जैसे <<-) असाइन करने के लिए काम करता है । यदि एक बेहतर, अधिक सामान्य समाधान है, तो pls। मुझे टिप्पणियों में बताएं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.