3.7 Correct Check (G)

Purpose: Checks whether the student’s tibble and the answer key are essentially the same. If so, full points are awarded.

Motivation: This Check is the most important. It allows for some flexibility between the student’s answer and the answer key, such as minor variations in column order, row order, rounding, and object attributes.

#Correct Check Example

else if(isTRUE(all.equal(variable_name |> ungroup() |> 
                         select(colnames(variable_name_test)) |> 
                         arrange(across(everything())), 
                         variable_name_test |> ungroup() |> 
                         select(colnames(variable_name_test)) |> 
                         arrange(across(everything())), 
                         tolerance = 0.001, check.attributes = F))){
  test.results[2, 2] <- 20 #Full credit
  test.results[2, 4] <- "Well done!"
}

Technicals

Always include the Correct Check.

Place this Check last (the last else if or the else statement).

This Check assumes that the student’s column names match the answer key, which is why the Column Name Check is essential beforehand.1

We set the tolerance to a small value (i.e., 0.001) to allow for some flexibility in numeric rounding, because different orders of operation can produce slightly different numbers due to how floats are handled by the computer.

The argument check.attributes = F ignores the attributes (essentially the additional information attached to an R object) when comparing the student’s answer to the answer key. In other words, we still want to award full credit to a student’s answer that looks virtually identical to the solution, but contains internally different metadata.

  • For example, the function na.omit() attaches an attribute to a tibble, making it internally different but visually identical to a tibble produced with drop_na(). Similarly, answers generated by the tabyl() function versus those created through a string of mutate() and summarize() functions.

The Correct Check can easily be adapted for named lists by swapping colnames() for names() and for vectors by implementing a reduced version of this Check.


  1. Acknowledgment: Previously, all_equal() was used for this Check. However, since all_equal() was deprecated in dplyr 1.1.0, we opted to use all.equal() instead. Unfortunately, because all.equal() does not contain the ignore_col_order and ignore_row_order arguments that allow for different column and row ordering, we had to implement this flexibility manually.↩︎