title: Gather multiple sets of columns
body: <p>I have data from an online survey where respondents go through a loop of questions 1-3 times. The survey software (Qualtrics) records this data in multiple columns—that is, Q3.2 in the survey will have columns <code>Q3.2.1.</code>, <code>Q3.2.2.</code>, and <code>Q3.2.3.</code>: </p>
  
  <pre><code>df &lt;- data.frame(
    id = 1:10,
    time = as.Date('2009-01-01') + 0:9,
    Q3.2.1. = rnorm(10, 0, 1),
    Q3.2.2. = rnorm(10, 0, 1),
    Q3.2.3. = rnorm(10, 0, 1),
    Q3.3.1. = rnorm(10, 0, 1),
    Q3.3.2. = rnorm(10, 0, 1),
    Q3.3.3. = rnorm(10, 0, 1)
  )
  
  # Sample data
  
     id       time    Q3.2.1.     Q3.2.2.    Q3.2.3.     Q3.3.1.    Q3.3.2.     Q3.3.3.
  1   1 2009-01-01 -0.2059165 -0.29177677 -0.7107192  1.52718069 -0.4484351 -1.21550600
  2   2 2009-01-02 -0.1981136 -1.19813815  1.1750200 -0.40380049 -1.8376094  1.03588482
  3   3 2009-01-03  0.3514795 -0.27425539  1.1171712 -1.02641801 -2.0646661 -0.35353058
  ...
  </code></pre>
  
  <p>I want to combine all the QN.N* columns into tidy individual QN.N columns, ultimately ending up with something like this:</p>
  
  <pre><code>   id       time loop_number        Q3.2        Q3.3
  1   1 2009-01-01           1 -0.20591649  1.52718069
  2   2 2009-01-02           1 -0.19811357 -0.40380049
  3   3 2009-01-03           1  0.35147949 -1.02641801
  ...
  11  1 2009-01-01           2 -0.29177677  -0.4484351
  12  2 2009-01-02           2 -1.19813815  -1.8376094
  13  3 2009-01-03           2 -0.27425539  -2.0646661
  ...
  21  1 2009-01-01           3 -0.71071921 -1.21550600
  22  2 2009-01-02           3  1.17501999  1.03588482
  23  3 2009-01-03           3  1.11717121 -0.35353058
  ...
  </code></pre>
  
  <p>The <code>tidyr</code> library has the <code>gather()</code> function, which works great for combining <em>one</em> set of columns:</p>
  
  <pre><code>library(dplyr)
  library(tidyr)
  library(stringr)
  
  df %&gt;% gather(loop_number, Q3.2, starts_with("Q3.2")) %&gt;% 
    mutate(loop_number = str_sub(loop_number,-2,-2)) %&gt;%
    select(id, time, loop_number, Q3.2)
  
  
     id       time loop_number        Q3.2
  1   1 2009-01-01           1 -0.20591649
  2   2 2009-01-02           1 -0.19811357
  3   3 2009-01-03           1  0.35147949
  ...
  29  9 2009-01-09           3 -0.58581232
  30 10 2009-01-10           3 -2.33393981
  </code></pre>
  
  <p>The resultant data frame has 30 rows, as expected (10 individuals, 3 loops each). However, gathering a second set of columns does not work correctly—it successfully makes the two combined columns <code>Q3.2</code> and <code>Q3.3</code>, but ends up with 90 rows instead of 30 (all combinations of 10 individuals, 3 loops of Q3.2, and 3 loops of Q3.3; the combinations will increase substantially for each group of columns in the actual data):</p>
  
  <pre><code>df %&gt;% gather(loop_number, Q3.2, starts_with("Q3.2")) %&gt;% 
    gather(loop_number, Q3.3, starts_with("Q3.3")) %&gt;%
    mutate(loop_number = str_sub(loop_number,-2,-2))
  
  
     id       time loop_number        Q3.2        Q3.3
  1   1 2009-01-01           1 -0.20591649  1.52718069
  2   2 2009-01-02           1 -0.19811357 -0.40380049
  3   3 2009-01-03           1  0.35147949 -1.02641801
  ...
  89  9 2009-01-09           3 -0.58581232 -0.13187024
  90 10 2009-01-10           3 -2.33393981 -0.48502131
  </code></pre>
  
  <p>Is there a way to use multiple calls to <code>gather()</code> like this, combining small subsets of columns like this while maintaining the correct number of rows?</p>