5

I am trying to build a Shiny app that is a search engine. I am returning a data.table based on the search keywords:

DT <- data.table(field = c("A_B_C","A_C_D","A_D_A","B_A_D","B_C_F","B_D_K"))

DT[field %like% "A|B"]

The above returns all fields containing A OR B. If I want to have A & B:

DT[field %like% "A"][field %like% "B"]

Is there a syntax that will allow me to do the above for any number of keywords. Something like:

DT[field %like% "A & B & C"]
Frank
  • 66,179
  • 8
  • 96
  • 180
Ivan P.
  • 480
  • 2
  • 5
  • 10

2 Answers2

17

If there are only two elements, compare them separately, then do a & and subset the dataset

DT[field %like% "A" & field %like% "B"]
#  field
#1: A_B_C
#2: B_A_D

If there are many strings to compare use Reduce with Map.

DT[Reduce(`&`, Map(`%like%`, list(field), c("A", "B")))]
#    field
#1: A_B_C
#2: B_A_D
akrun
  • 874,273
  • 37
  • 540
  • 662
6

Or you can use Perl-style regex, in combination with grepl inside your data.table:

pat <- "(?=.*A)(?=.*B)"
DT[grep(pat, field, perl = TRUE),]
#   field
#1: A_B_C
#2: B_A_D
mtoto
  • 23,919
  • 4
  • 58
  • 71
  • 2
    Could also show how to move from a query to that pattern, like `query = "A & B"; library(magrittr); pat = query %>% sub("^\\s*", "(?=.*", x = .) %>% sub("\\s*$", ")", x = .) %>% sub("\\s*&\\s*", ")(?=.*", x = .) ` – Frank Oct 19 '16 at 12:27
  • With a vector of search terms like `terms <- c("A", "B")`, you can use `DT[grepl(paste(sprintf("(?=.*%s)", terms), collapse=""), field, perl=TRUE)]`. – dnlbrky May 12 '17 at 01:25