I am slightly new to writing functions in R. Here I have a basic function that searches for a pattern and returns the indexes of where the occurence occurs given a list dataset

#this functions takes a pattern and prints the indexes for the matches
find_domain <- function(pattern,list) grep(pattern,list,ignore.case=T)

Sometimes during the analysis i found that i need to do that for a larger dataset. The idea is to look for occurence of a domain (pattern) in each of the d7_dataset rows(since each row represents a protein sequence and each column is a domain) such that i can then count the number of sequences that contain or have a given domain(pattern in this case) So i wrote this

seqs <- c()
for (i in 1:nrow(d7_dataset)){
       pos <- find_domain("CIDRγ13",d7_dataset[i,])
       if (!is.na(pos[1])) 
        seqs <- c(seqs,1)  

total_seqs <- sum(seqs)

However this seems like it can be written as a single function so that i can eliminate duplication and simplify it such that it is generic enough to apply to multiple datasets. Any ideas on how to condence it to a single function? In a nutshell, Given a pattern or list of patterns and a dataset(as a dataframe) to search, return the number of sequences(rows in the dataset) that contain the given pattern.

More or less like this

results <– search(a list of patterns to search,dataset)

results should look like

pattern  count
 pat1     40
 pat2      3
 pat3      0
 .         . 
 .         .

It would be very good if the pattern argument would accept a list to search

Thank you

  • $\begingroup$ Just a programming note: it is useless (and will slow down your script) to create a function that just calls another function. There is no real advantage in calling find_domain if the only thing it does it's calling grep. You are just adding the overhead of another function call. $\endgroup$
    – nico
    Jan 5, 2011 at 17:47
  • $\begingroup$ you are right! this was a dirty approach and just sounded sort of wrong design though it worked. Am glad that i asked! $\endgroup$
    – eastafri
    Jan 5, 2011 at 17:55

2 Answers 2


If your dataset is a matrix, then grep will work directly:

> set.seed(1)
> bb=matrix(letters[sample(1:20, 100, rep=TRUE)], nrow=20)
> grep("b", bb)
 [1] 10 55 56 69 92
> bb[grep("b", bb)]
[1] "b" "b" "b" "b" "b"

If you have multiple patterns, then use ldply from package plyr:

> ldply(c("a", "b", "z"), function(l) data.frame(pattern = l, count = length(grep(l, bb))))
    pattern count
  1       a     2
  2       b     5
  3       z     0

Your function search then can look like this

 search <- function(patlist,data) {
      if(!is.matrix(data)) data <- as.matrix(data)
      ldply(patlist, function(l) data.frame(pattern = l, count = length(grep(l, bb))))

Note that this will not work for data.frame. So if that is possible you will need to convert it to the matrix, as I did in the code above.

  • $\begingroup$ @mpitkas (+1) Nice one! $\endgroup$
    – chl
    Jan 5, 2011 at 14:13
  • $\begingroup$ @mpitkas Ah, and yours is faster (by 0.004, on my fake data set). This the way to go... $\endgroup$
    – chl
    Jan 5, 2011 at 14:18
  • $\begingroup$ And sorry to have mispelled your name (two times) :( $\endgroup$
    – chl
    Jan 5, 2011 at 14:23
  • $\begingroup$ @chl, no worries, my surname is constantly misspelled by my native language speakers, so my expectations for not misspelling the nickname are really low :) $\endgroup$
    – mpiktas
    Jan 5, 2011 at 14:35

You should first replace your for loop with something like apply(d7_dataset, 1, foo), where foo() is either your function or something along those lines, e.g. gregexpr(). The result of gregexpr() is a list of numeric vectors with attributes similar to regexpr() but giving all matches in each element.

On a related point, there was another function that was proposed as a more user-friendly alternative to gregexpr(): easyGregexpr.

The following example gives you the number of matches for each row when considering a list of three motifs (in a 10x100 matrix):

dd <- replicate(100, replicate(10, paste(sample(letters[1:4], 2),    
pat <- list("aa", "ab", "cd")
foo <- function(d, p) apply(d, 1, function(x) length(grep(p, x)))
lapply(pat, function(x) foo(dd, x))
  • 1
    $\begingroup$ for this purpose you can see the stringr package of H. Wickam $\endgroup$
    – pbneau
    Jan 5, 2011 at 13:56
  • $\begingroup$ Thanks for pointing out the rstring library!! Awesome approaches! Thanks! $\endgroup$
    – eastafri
    Jan 5, 2011 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.