Jak pojawia się pytanie, czy istnieje sekwencja kontrolna w R podobna do operatora trójskładnikowego C ? Jeśli tak, jak z niego korzystasz? Dzięki!
if (x>1) y=2 else y=3. Pisanie y=raz ma do tego pewien urok.
Jak pojawia się pytanie, czy istnieje sekwencja kontrolna w R podobna do operatora trójskładnikowego C ? Jeśli tak, jak z niego korzystasz? Dzięki!
if (x>1) y=2 else y=3. Pisanie y=raz ma do tego pewien urok.
Odpowiedzi:
Tak jak iffunkcja w Ri zwraca ostatnią ocenę, jeśli-else jest równoważne ?:.
> a <- 1
> x <- if(a==1) 1 else 2
> x
[1] 1
> x <- if(a==2) 1 else 2
> x
[1] 2
Moc R to wektoryzacja. Wektoryzacja operatora trójskładnikowego to ifelse:
> a <- c(1, 2, 1)
> x <- ifelse(a==1, 1, 2)
> x
[1] 1 2 1
> x <- ifelse(a==2, 1, 2)
> x
[1] 2 1 2
Żartuję, możesz zdefiniować styl c ?::
`?` <- function(x, y)
eval(
sapply(
strsplit(
deparse(substitute(y)),
":"
),
function(e) parse(text = e)
)[[2 - as.logical(x)]])
tutaj nie musisz dbać o nawiasy:
> 1 ? 2*3 : 4
[1] 6
> 0 ? 2*3 : 4
[1] 4
> TRUE ? x*2 : 0
[1] 2
> FALSE ? x*2 : 0
[1] 0
ale potrzebujesz nawiasów do przypisania :(
> y <- 1 ? 2*3 : 4
[1] 6
> y
[1] 1
> y <- (1 ? 2*3 : 4)
> y
[1] 6
Wreszcie możesz zrobić bardzo podobny sposób z c:
`?` <- function(x, y) {
xs <- as.list(substitute(x))
if (xs[[1]] == as.name("<-")) x <- eval(xs[[3]])
r <- eval(sapply(strsplit(deparse(substitute(y)), ":"), function(e) parse(text = e))[[2 - as.logical(x)]])
if (xs[[1]] == as.name("<-")) {
xs[[3]] <- r
eval.parent(as.call(xs))
} else {
r
}
}
Możesz pozbyć się nawiasów:
> y <- 1 ? 2*3 : 4
> y
[1] 6
> y <- 0 ? 2*3 : 4
> y
[1] 4
> 1 ? 2*3 : 4
[1] 6
> 0 ? 2*3 : 4
[1] 4
Nie są one do codziennego użytku, ale mogą być przydatne do nauki niektórych wewnętrznych elementów języka R.
Jak wszyscy mówili, użyj ifelse, ale możesz zdefiniować operatory, aby uzyskać prawie trójskładnikową składnię operatorów.
`%?%` <- function(x, y) list(x = x, y = y)
`%:%` <- function(xy, z) if(xy$x) xy$y else z
TRUE %?% rnorm(5) %:% month.abb
## [1] 0.05363141 -0.42434567 -0.20000319 1.31049766 -0.31761248
FALSE %?% rnorm(5) %:% month.abb
## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
# or, more generally
condition %?% value1 %:% value2
W rzeczywistości działa, jeśli zdefiniujesz operatory bez %znaków, więc możesz to zrobić
`?` <- function(x, y) if(x) y[[1]] else y[[2]]
`:` <- function(y, z) list(y, z)
TRUE ? rnorm(5) : month.abb
## [1] 1.4584104143 0.0007500051 -0.7629123322 0.2433415442 0.0052823403
FALSE ? rnorm(5) : month.abb
## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
(Działa to, ponieważ pierwszeństwo :jest mniejsze niż ?).
Niestety, to zrywa istniejącą pomoc i operatory sekwencji.
Tylko jako żart, to może przedefiniować ?operatorowi (prawie) jak praca operatora potrójnego (jest to zły pomysł):
`?` <- function(x, y) { y <-substitute(y); if(x) eval(y[[2]], parent.frame()) else eval(y[[3]], parent.frame()) }
x <- 1:3
length(x) ? (x*2) : 0
x <- numeric(0)
length(x) ? (x*2) : 0
for(i in 1:5) cat(i, (i %% 2) ? "Odd\n" : "Even\n")
... Ale musisz umieścić wyrażenia w nawiasach, ponieważ domyślny priorytet nie jest taki jak w C.
Pamiętaj tylko, aby przywrócić starą funkcję pomocy, gdy skończysz grać:
rm(`?`)
Rzuciłem okiem na ifelsepolecenie. Nazwałbym to jeszcze lepiej, ponieważ jest również zwektoryzowany. Przykład wykorzystujący zbiór danych samochodów:
> cars$speed > 20
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
[49] TRUE TRUE
> ifelse(cars$speed > 20, 'fast', 'slow')
[1] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow"
[11] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow"
[21] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow"
[31] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow"
[41] "slow" "slow" "slow" "fast" "fast" "fast" "fast" "fast" "fast" "fast"
ifelseswoim przykładem? ;)
Twój link wskazuje na ifoświadczenie.
> x <- 1
> if(x < 2) print("Less than") else print("Greater than")
[1] "Less than"
Jeśli zmienną wejściową jest wektor, ifelsemoże być bardziej odpowiednie:
> x <- 1:3
> ifelse(x<=2, "Less than or equal", "Greater than")
[1] "Less than or equal" "Less than or equal" "Greater than"
Aby uzyskać dostęp do strony pomocy dla if, musisz osadzić iflewe znaczniki:
?`if`
Strona pomocy dla ifelse:
`?ifelse`
print(if (x<2) "Less than" else "Greater than")
Nie istnieje, ale możesz to zrobić:
set.seed(21)
y <- 1:10
z <- rnorm(10)
condition1 <- TRUE
x1 <- if(condition1) y else z
lub
condition2 <- sample(c(TRUE,FALSE),10,TRUE)
x2 <- ifelse(condition2, y, z)
Różnica pomiędzy nimi jest to, że condition1musi być logicznie wektor o długości 1, a condition2musi być logicznie wektor tej samej długości x, yoraz z. Pierwsza zwróci albo ylub z(cały obiekt), podczas gdy druga zwróci odpowiedni element y( condition2==TRUE) lub z( condition2==FALSE).
Należy także zwrócić uwagę, że ifelsejest dłuższy niż if/ elsejeśli condition, yi zsą wektorami o długości 1.
if działa jak niewektorowany ifelse, jeśli jest używany w następujący sposób:
`if`(condition, doIfTrue, doIfFalse)
Zaletą korzystania z tego w porównaniu z ifelse jest sytuacja, w której wektoryzacja jest przeszkodą (tj. Mam w rezultacie skalarną wartość logiczną i listę / wektor)
ifelse(TRUE, c(1,2), c(3,4))
[1] 1
`if`(TRUE, c(1,2), c(3,4))
[1] 1 2
ifelse, czy po prostu bardziej kompaktowej formy?