title: Apply Function Across Columns in data.table with do.call and .SD in R
body: <p>I'm trying to create a variant of <code>pmax</code> / <code>pmin</code> that works with an additional <code>filter_value</code> parameter across an arbitrary set of columns that would be defined using <code>.SD</code> / <code>.SDcols</code>.  The first version of the function below hard-codes the filter value, but works with <code>.SD</code>:</p>
  
  <pre><code>testFuncV1 &lt;- function(...) { 
    cols &lt;- list(...)
    num_cols &lt;- length(cols)
    num_records &lt;- length(cols[[1]])
    max_records &lt;- c()
    for (record_num in 1:num_records) {
      v &lt;- c()
      for (l in cols) {
        v &lt;- c(v, l[[record_num]])
      }
      filt_v &lt;- Filter(function(x) { x &lt;= 1 }, v)
      if (length(filt_v) == 0) {
        max_records &lt;- c(max_records, NA) 
      } else {
        max_records &lt;- c(max_records, max(filt_v))
      }
    }
    max_records
  }
  
  test_dt_v1 &lt;- data.table(a = c(1,3,5), b = c(2,3,-1), c = c(-3, 5, 2))
  
  test_dt_v1[, max_with_filter := do.call(testFuncV1, .SD), .SDcols = c('a', 'b', 'c')]
  </code></pre>
  
  <p>returns:</p>
  
  <pre><code>   a  b  c max_with_filter
  1: 1  2 -3               1
  2: 3  3  5              NA
  3: 5 -1  2              -1
  </code></pre>
  
  <p>The second version of the function below takes a second <code>filter</code> parameter, but I was not able to get it to work with <code>.SD</code>, and rather, had to pass the individual column vectors in as a list to get things to work:</p>
  
  <pre><code>testFuncV2 &lt;- function(cols, filter) { 
    num_cols &lt;- length(cols)
    num_records &lt;- length(cols[[1]])
    max_records &lt;- c()
    for (record_num in 1:num_records) {
      v &lt;- c()
      for (l in cols) {
        v &lt;- c(v, l[[record_num]])
      }
      filt_v &lt;- Filter(function(x) { x &lt;= filter }, v)
      if (length(filt_v) == 0) {
        max_records &lt;- c(max_records, NA) 
      } else {
        max_records &lt;- c(max_records, max(filt_v))
      }
    }
    max_records
  }
  
  test_dt_v2 &lt;- data.table(a = c(1,3,5), b = c(2,3,-1), c = c(-3, 5, 2))
  
  test_dt_v2[, max_with_filter := do.call(testFuncV2, list(list(test_dt_v2$a, test_dt_v2$b, test_dt_v2$c), 1))]
  </code></pre>
  
  <p>also returns:</p>
  
  <pre><code>   a  b  c max_with_filter
  1: 1  2 -3               1
  2: 3  3  5              NA
  3: 5 -1  2              -1
  </code></pre>
  
  <p>Ideally, I'd be able to either figure out an approach that works with <code>.SD</code> using <code>do.call</code>, or substitute in something that works with <code>lapply</code> (which I also experimented around with, to no avail).  Thanks in advance!</p>