Như câu hỏi đặt ra, có một chuỗi điều khiển trong R tương tự như toán tử ternary của C không? Nếu vậy, làm thế nào để bạn sử dụng nó? Cảm ơn!
if (x>1) y=2 else y=3
. Viết y=
một lần có một sức hấp dẫn nhất định với nó.
Như câu hỏi đặt ra, có một chuỗi điều khiển trong R tương tự như toán tử ternary của C không? Nếu vậy, làm thế nào để bạn sử dụng nó? Cảm ơn!
if (x>1) y=2 else y=3
. Viết y=
một lần có một sức hấp dẫn nhất định với nó.
Câu trả lời:
Là if
chức năng trong R
và trả về đánh giá mới nhất, if-other tương đương với ?:
.
> a <- 1
> x <- if(a==1) 1 else 2
> x
[1] 1
> x <- if(a==2) 1 else 2
> x
[1] 2
Sức mạnh của R là vector hóa. Các vector hóa của toán tử ternary là 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
Đùa thôi, bạn có thể định nghĩa kiểu c ?:
:
`?` <- function(x, y)
eval(
sapply(
strsplit(
deparse(substitute(y)),
":"
),
function(e) parse(text = e)
)[[2 - as.logical(x)]])
Ở đây, bạn không cần quan tâm đến dấu ngoặc:
> 1 ? 2*3 : 4
[1] 6
> 0 ? 2*3 : 4
[1] 4
> TRUE ? x*2 : 0
[1] 2
> FALSE ? x*2 : 0
[1] 0
nhưng bạn cần dấu ngoặc để gán :(
> y <- 1 ? 2*3 : 4
[1] 6
> y
[1] 1
> y <- (1 ? 2*3 : 4)
> y
[1] 6
Cuối cùng, bạn có thể làm cách tương tự với 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
}
}
Bạn có thể thoát khỏi dấu ngoặc:
> 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
Đây không phải là để sử dụng hàng ngày, nhưng có thể tốt cho việc học một số nội bộ của ngôn ngữ R.
Giống như mọi người khác đã nói, hãy sử dụng ifelse
, nhưng bạn có thể xác định các toán tử để bạn gần như có cú pháp toán tử ternary.
`%?%` <- 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
Nó thực sự hoạt động nếu bạn xác định các toán tử mà không có %
dấu hiệu, vì vậy bạn có thể có
`?` <- 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"
(Điều này hoạt động vì mức độ ưu tiên :
thấp hơn ?
.)
Thật không may, sau đó phá vỡ các toán tử trợ giúp và trình tự hiện có.
Cũng giống như một trò chơi khăm, bạn có thể xác định lại ?
toán tử để (gần như) hoạt động giống như toán tử ternary (ĐÂY LÀ MỘT BAD IDEA):
`?` <- 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")
... Nhưng bạn cần đặt các biểu thức trong ngoặc đơn vì quyền ưu tiên mặc định không giống như trong C.
Chỉ cần nhớ khôi phục chức năng trợ giúp cũ khi bạn chơi xong:
rm(`?`)
Tôi sẽ xem ifelse
lệnh. Tôi sẽ gọi nó thậm chí còn tốt hơn bởi vì nó cũng được vector hóa. Một ví dụ sử dụng bộ dữ liệu xe hơi:
> 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"
ifelse
với ví dụ của bạn? ;)
Liên kết của bạn trỏ đến một if
tuyên bố.
> x <- 1
> if(x < 2) print("Less than") else print("Greater than")
[1] "Less than"
Nếu biến đầu vào của bạn là một vectơ, thì ifelse
có thể phù hợp hơn:
> x <- 1:3
> ifelse(x<=2, "Less than or equal", "Greater than")
[1] "Less than or equal" "Less than or equal" "Greater than"
Để truy cập trang trợ giúp if
, bạn cần nhúng các if
backticks:
?`if`
Trang trợ giúp dành cho ifelse
:
`?ifelse`
print(if (x<2) "Less than" else "Greater than")
Nó không tồn tại rõ ràng, nhưng bạn có thể làm:
set.seed(21)
y <- 1:10
z <- rnorm(10)
condition1 <- TRUE
x1 <- if(condition1) y else z
hoặc là
condition2 <- sample(c(TRUE,FALSE),10,TRUE)
x2 <- ifelse(condition2, y, z)
Sự khác biệt giữa hai là condition1
phải là một vector logic có độ dài 1, trong khi condition2
phải là một vector logic cùng độ dài như x
, y
, và z
. Đầu tiên sẽ trở lại một trong hai y
hoặc z
(toàn bộ đối tượng), trong khi thứ hai sẽ trở lại các yếu tố tương ứng của y
( condition2==TRUE
) hoặc z
( condition2==FALSE
).
Cũng lưu ý rằng ifelse
sẽ chậm hơn so if
/ else
nếu condition
, y
và z
đều là những vectơ với chiều dài 1.
if
hoạt động như ifelse unvectorised nếu được sử dụng theo cách sau:
`if`(condition, doIfTrue, doIfFalse)
Ưu điểm của việc sử dụng này so với ifelse là khi kết quả vector hóa (nghĩa là tôi có kết quả boolean vô hướng và liệt kê / vectơ)
ifelse(TRUE, c(1,2), c(3,4))
[1] 1
`if`(TRUE, c(1,2), c(3,4))
[1] 1 2
ifelse
, hoặc chỉ là một hình thức nhỏ gọn hơn?