分配交替:分配值时为OR

时间:2016-07-05 16:23:21

标签: r

我有几个变量(来自解析文本),可能是也可能不是空字符串。我想尝试将几个备用变量的第一个真值用于新的规范变量。类似的东西:

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中实现此目的?

3 个答案:

答案 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个函数(applywhichifelse)。您是否希望它包含在一个允许您不必创建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)。请注意,NANULL上的此特定实施将失败,如果foobarquux有多个值,则会发出警告(输入is.na },is.nullassertthat::is.string用于检查输入。)

当然,dplyr::coalescedplyr::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 )
}