1

Can the ! operator, or its opposite, be assigned dynamically to a variable then serve as a calculation input? There is a set of data.frames whose subsets I switch depending on a T/F condition.  Here’s an example, where earlier code determines whether m.true.false is true or false., or m.true.false is an argument to a function.

m.true.false <- T  #  or in other instances, F
df.1 <- data.frame(cell.id = 1:10, predictor = runif(n = 10))  
# and there are a bunch of similar data frames.
test.cells <- c(1, 4:6)

if (m.true.false) {
    subset.1 <- df.1[df.1$cell.id %in% test.cells, ]
} else {
    subset.1 <- df.1[!df.1$cell.id %in% test.cells, ]
}

I would like to use or modify m.true.false so that m.true.false is a simple input to a single set of the subsetting commands, inverting the choice of which rows of each data frame to keep.  This shows the concept but yields an empty set.

subset.1 <- df.1[m.true.false * (df.1$cell.id %in% test.cells), ]

A medium-ugly solution is:

helper.true.false <- ifelse(m.true.false, 0, 1)
subset.1 <- df.1[as.logical(abs((df.1$cell.id %in% test.cells) - helper.true.false)), ]

Is there a simpler alternative?  As an MRE the difference is minor, but I have multiple comparable uses.

Answers to these questions work if m.true.false is static:  Opposite of %in%: exclude rows with values specified in a vector, Negation of %in% in R

InColorado
  • 308
  • 2
  • 12

1 Answers1

1

Just conditionally return your logical vector or your negated logical vector:

idx <- df.1$cell.id %in% test.cells
df.1[if (m.true.false) idx else !idx,]

You could define a function that returns your row selection and then use Negate to conditionally reverse this selection:

set.seed(1)

m.true.false <- F  #  or in other instances, F
df.1 <- data.frame(cell.id = 1:10, predictor = runif(n = 10))  
# and there are a bunch of similar data frames.
test.cells <- c(1, 4:6)

f <- \() df.1$cell.id %in% test.cells
f <- if (m.true.false) f else Negate(f)

df.1[f(),]

Or create a function where you pass the logical vector and it searched your global environment for m.true.false and makes the adjustment accordingly. In this way you can use it with any condition:

f <- function(x) {
  if (m.true.false) x else !x
}

df.1[f(df.1$cell.id %in% test.cells),]
LMc
  • 12,577
  • 3
  • 31
  • 43
  • 1
    That first 2-liner is exactly what I wanted. I've never seen or imagined an if statement within selection brackets and it works perfectly. – InColorado Jul 31 '23 at 19:18