title: Convert columns of arbitrary class to the class of matching columns in another data.table
body: <p><strong>Question:</strong></p>
  
  <p>I'm working in R. I want the shared columns of 2 data.tables (shared meaning same column name) to have matching classes. I'm struggling with a way to generically convert an object of unknown class to the unknown class of another object.</p>
  
  <hr>
  
  <p><strong>More context:</strong></p>
  
  <p>I know how to set the class of a column in a data.table, and I know <em>about</em> the <code>as</code> function. Also, this question isn't entirely <code>data.table</code> specific, but it comes up often when I use <code>data.table</code>s. Further, assume that the desired coercion is possible.</p>
  
  <p>I have 2 data.tables. They share some column names, and those columns are intended to represent the same information. For the column names shared by table A and table B, I want the classes of A to match those in B (or other way around).</p>
  
  <hr>
  
  <p><strong>Example <code>data.table</code>s:</strong></p>
  
  <pre><code>A &lt;- structure(list(year = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L)), .Names = c("year", "stratum"), row.names = c(NA, -45L), class = c("data.table", "data.frame"))
  
  B &lt;- structure(list(year = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), stratum = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L), bt = c(-9.95187702337873, -9.48946944434626, -9.74178662514147, -5.36167545158338, -4.76405522202426, -5.41964239804882, -0.0807951335119085, 0.520481719699774, 0.0393874225863578, 5.40557402913123, 5.47927931969583, 5.37228402911139, 9.82774396910091, 9.89629694010177, 9.98105260936272, -9.82469892896284, -9.42530210357904, -9.66171049964775, -5.17540952901709, -4.81859082470115, -5.3577146169737, -0.0685310909609001, 0.441383303157166, -0.0105897444321987, 5.24205882775199, 5.65773605162835, 5.40217185632441, 9.90299445851434, 9.78883672575814, 9.98747998379124, -9.69843398105195, -9.31530717395811, -9.77406601252698, -4.83080164375344, -4.89056304189872, -5.3904000267275, -0.121508487954861, 0.493798577602088, -0.118550709142654, 5.23654772583187, 5.87760447006892, 5.22478092346285, 9.90949768116403, 9.85433376398086, 9.91619307289277), yr = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)), .Names = c("year", "stratum", "bt", "yr"), row.names = c(NA, -45L), class = c("data.table", "data.frame"), sorted = c("year", "stratum"))
  </code></pre>
  
  <p>Here's what they look like:</p>
  
  <pre><code>&gt; A  
      year stratum
   1:    1       1
   2:    1       2
   3:    1       3
   4:    1       4
  
  &gt; B
      year stratum          bt yr
   1:    1       1 -9.95187702  1
   2:    1       2 -9.48946944  1
   3:    1       3 -9.74178663  1
   4:    1       4 -5.36167545  1
  </code></pre>
  
  <p>Here are the classes:</p>
  
  <pre><code>&gt; sapply(A, class)
       year   stratum 
  "integer" "integer"
  
  &gt; sapply(B, class)
       year   stratum        bt        yr 
  "numeric" "integer" "numeric" "numeric"
  </code></pre>
  
  <p>Manually, I can accomplish the desired task through the following:</p>
  
  <pre><code>A[,year:=as.numeric(year)]
  </code></pre>
  
  <p>This is easy when there's only 1 column to change, you know that column ahead of time, and you know the desired class ahead of time. If desired, it's also pretty easy to to convert arbitrary columns to a given class. I also know how to convert arbitrary columns to any given class. </p>
  
  <hr>
  
  <p><strong>My Failed Attempt:</strong></p>
  
  <p><strong>(EDIT: This actually works; see my answer)</strong></p>
  
  <pre><code>s2c &lt;- function (x, type = "list") 
  {
      as.call(lapply(c(type, x), as.symbol))
  }
  
  # In this case, I can assume all columns of A can be found in B
  # I am also able to assume that the desired conversion is possible
  B.class &lt;- sapply(B[,eval(s2c(names(A)))], class) 
  for(col in names(A)){
      set(A, j=col, value=as(A[[col]], B.class[col]))
  }
  </code></pre>
  
  <p>But this still returns the year column as <code>"integer"</code>, not <code>"numeric"</code>:  </p>
  
  <pre><code>&gt; sapply(A, class)
       year   stratum 
  "integer" "integer" 
  </code></pre>
  
  <p>The problem in the above example is that <code>class(as(1L, "numeric"))</code> still returns <code>"integer"</code>. On the other hand, <code>class(as.numeric(1L))</code> returns <code>"numeric"</code>; however, I don't know ahead of time that need <code>as.numeric</code> is needed.</p>
  
  <hr>
  
  <p><strong>Question, Restated:</strong></p>
  
  <p>How do I make the column classes match, when neither <em>columns</em> nor the <code>to</code>/<code>from</code> <em>classes</em> are known ahead of time?</p>
  
  <hr>
  
  <p><strong>Additional Thoughts:</strong></p>
  
  <p>In a way, the question is mostly about arbitrary class matching. I run into this issue often with data.table because it's very vocal about class matching. E.g., I run into similar problems when needed to insert <code>NA</code> of the appropriate type (<code>NA_real_</code> vs <code>NA_character_</code>, etc), depending on the class of the column (see related question/ issue in <a href="https://stackoverflow.com/questions/7960798/splitting-a-data-table-with-the-by-operator-functions-that-return-numeric-value/7960860#comment55090874_7960860">This Question</a>).</p>
  
  <p>Again, this question can be seen as a general issue of converting between arbitrary classes that aren't known in advance. In the past, I've written functions using <code>switch</code> to do something like <code>switch(class(x), double = as.numeric(...), character = as.character(...), ...</code>, but that seems a big ugly. The only reason I'm bringing this up in the context of data.table is because it's where I most often encounter the need for this type of functionality.</p>