我有几个变量(来自解析文本),可能是也可能不是空字符串。我想尝试将几个备用变量的第一个真值用于新的规范变量。类似的东西:
canon = foo || bar || quux || NA
如果foo=""
,bar="Barney"
,quux="Wilma"
然后canon="Barney"
,但如果bar
为空,canon="Wilma"
等,我目前可以获得以下内容错误:
Error in foo || bar : invalid 'x' type in 'x || y'
在R中查找逻辑分配的示例时,搜索错误没有任何帮助,也没有找到太多内容。如何在R中实现此目的?
答案 0 :(得分:1)
我认为问题在于||
仅用于检查值,其工作方式与您对其他语言的预期不同。
如果您可以在矩阵/ data.frame中包含所有值,则可以使用以下内容:
set.seed(12345)
df <-
data.frame(
foo = sample(c("",LETTERS),100
, TRUE, prob = c(1,rep(1/52,26)))
, bar = sample(c("",letters),100
, TRUE, prob = c(1,rep(1/52,26)))
, quux = sample(c("",1:26),100
, TRUE, prob = c(1,rep(1/52,26)))
)
# head(df)
canon <-
apply(df,1,function(x){
# Find the real values
realValues <- which(x != "")
ifelse(length(realValues) > 0 # Check if any real values exist
, x[realValues[1]] # if so, return the first one
, NA) # If not, return NA
})
你想要多少简单?这不是本机请求,但代码仍然只有3个函数(apply
,which
和ifelse
)。您是否希望它包含在一个允许您不必创建data.frame的函数中?如果这是你常用的东西,这可能是值得的。
makeCanon <- function(x, ...){
if(class(x) %in% c("data.frame","matrix")){
df <- x
} else{
df <- as.data.frame(list(x, ...))
}
out <-
apply(df,1,function(z){
realValues <- which(z != "")
ifelse(length(realValues) > 0
, z[realValues[1]]
, NA)
})
return(out)
}
fromDF <- makeCanon(df)
fromVectors <- makeCanon(df$foo, df$bar, df$quux)
table(fromDF == fromVectors)
答案 1 :(得分:1)
虽然矢量化选项可能是最佳选择,但如果您希望保留原始语法的可读性(?),则可以实现||
的变体:
"%||%" <- function(x, y) if (x == '') y else x
foo = ""
bar = "Barney"
quux = "Wilma"
canon = foo %||% bar %||% quux %||% NA
我已经看到了使用默认值替换NULL
参数的策略(来源:dplyr)。请注意,NA
和NULL
上的此特定实施将失败,如果foo
,bar
或quux
有多个值,则会发出警告(输入is.na
},is.null
和assertthat::is.string
用于检查输入。)
当然,dplyr::coalesce
和dplyr::na_if
看起来更加出色:
library(dplyr)
# Convert troublesome values to NA
foo = "" %>% na_if("")
bar = "Barney" %>% na_if("")
quux = "Wilma" %>% na_if("")
# Vectorized so foo, bar, etc. should be the same length or length of 1
canon = coalesce(foo, bar, quux)
答案 2 :(得分:0)
这是一个基于Mark解决方案的版本,它跳过了NULL,NA和空字符串。
library("gtools")
#Returns first real value, otherwise NA
canon = function(inputVector){
realValues = Filter(Negate(invalid), inputVector)
ifelse( length(realValues)>0, realValues[1], NA )
}