Câu trả lời được cung cấp bởi @ fabian-werner là tuyệt vời, nhưng các đối tượng có thể có nhiều lớp và "yếu tố" có thể không nhất thiết phải là lớp đầu tiên được trả về class(yes)
, vì vậy tôi đề nghị sửa đổi nhỏ này để kiểm tra tất cả các thuộc tính của lớp:
safe.ifelse <- function(cond, yes, no) {
class.y <- class(yes)
if ("factor" %in% class.y) { # Note the small condition change here
levels.y = levels(yes)
}
X <- ifelse(cond,yes,no)
if ("factor" %in% class.y) { # Note the small condition change here
X = as.factor(X)
levels(X) = levels.y
} else {
class(X) <- class.y
}
return(X)
}
Tôi cũng đã gửi yêu cầu với nhóm Phát triển R để thêm tùy chọn được ghi thành tài liệu để có các thuộc tính cơ sở :: ifelse () dựa trên lựa chọn của người dùng về các thuộc tính cần bảo tồn. Yêu cầu có ở đây: https://bugs.r-project.org/ormszilla/show_orms.cgi?id=16609 - Nó đã được gắn cờ là "WONTFIX" với lý do nó vẫn luôn như hiện tại, nhưng tôi đã cung cấp một lập luận tiếp theo về lý do tại sao một bổ sung đơn giản có thể cứu được rất nhiều người dùng R đau đầu. Có lẽ "+1" của bạn trong chuỗi lỗi đó sẽ khuyến khích nhóm R Core xem xét lại lần thứ hai.
EDIT: Đây là phiên bản tốt hơn cho phép người dùng chỉ định các thuộc tính cần bảo tồn, "hành vi" (mặc định ifelse ()), "có", hành vi theo mã ở trên hoặc "không", trong trường hợp các thuộc tính của giá trị "không" là tốt hơn:
safe_ifelse <- function(cond, yes, no, preserved_attributes = "yes") {
# Capture the user's choice for which attributes to preserve in return value
preserved <- switch(EXPR = preserved_attributes, "cond" = cond,
"yes" = yes,
"no" = no);
# Preserve the desired values and check if object is a factor
preserved_class <- class(preserved);
preserved_levels <- levels(preserved);
preserved_is_factor <- "factor" %in% preserved_class;
# We have to use base::ifelse() for its vectorized properties
# If we do our own if() {} else {}, then it will only work on first variable in a list
return_obj <- ifelse(cond, yes, no);
# If the object whose attributes we want to retain is a factor
# Typecast the return object as.factor()
# Set its levels()
# Then check to see if it's also one or more classes in addition to "factor"
# If so, set the classes, which will preserve "factor" too
if (preserved_is_factor) {
return_obj <- as.factor(return_obj);
levels(return_obj) <- preserved_levels;
if (length(preserved_class) > 1) {
class(return_obj) <- preserved_class;
}
}
# In all cases we want to preserve the class of the chosen object, so set it here
else {
class(return_obj) <- preserved_class;
}
return(return_obj);
} # End safe_ifelse function
if_else()
trong gói dplyr có thể thay thếifelse
trong khi vẫn giữ đúng các lớp đối tượng Date - nó được đăng dưới đây như một câu trả lời gần đây. Tôi đang chú ý đến nó ở đây vì nó giải quyết vấn đề này bằng cách cung cấp một chức năng được kiểm tra đơn vị và ghi lại trong gói CRAN, không giống như nhiều câu trả lời khác (như nhận xét này) được xếp trước nó.