Skip to content

Instantly share code, notes, and snippets.

@leeper
Last active September 11, 2016 17:22
Show Gist options
  • Save leeper/0ca26a9bf9002b6c7bd5640d97977f84 to your computer and use it in GitHub Desktop.
Save leeper/0ca26a9bf9002b6c7bd5640d97977f84 to your computer and use it in GitHub Desktop.
Compare two data.frames and generate the code to patch the differences
# function to identify what changed where
which_changed <- function(x, y = x) {
# argument validation
stopifnot(inherits(x, "data.frame"))
stopifnot(inherits(y, "data.frame"))
stopifnot(identical(dim(x), dim(y)))
y <- y[, names(x)]
# compare objects
w <- which(as.vector(!(x == y)))
if (length(w)) {
rowpos <- w %% nrow(x)
colpos <- names(x)[(w %/% nrow(x)) + 1]
values <- list()
for (i in seq_along(rowpos)) {
values[[i]] <- y[rowpos[i], colpos[i], drop = FALSE]
}
out <- mapply(function(row, col, val) {
list(x = row, y = col, value = val)
}, rowpos, colpos, values, SIMPLIFY = FALSE)
} else {
out <- list()
}
structure(out, class = "data_diff")
}
# print function
print.data_diff <- function(x, ...) {
message(paste0("Data differs in ", length(x), ngettext(length(x), " place", " places")))
invisible(x)
}
# function to make code to change `x` into `y`
make_data_patch <- function(x, y = x) {
diff <- which_changed(x, y)
if (length(diff)) {
xname <- as.character(substitute(x))
changes <- lapply(diff, function(change) {
paste0(xname, "[", change[["x"]], ", '", change[["y"]], "'] <- ", change[["value"]])
})
out <- paste0(unlist(changes), collapse = "\n")
} else {
out <- paste0("# no value changes to make")
}
}
# Examples
# example with no changes
(chg1 <- which_changed(mtcars, mtcars))
## Data differs in 0 places
p1 <- make_patch_code(mtcars, mtcars)
cat(p1, "\n")
## # no value changes to make
# example with changes
mtcars1 <- mtcars
mtcars2 <- mtcars
mtcars2[3,4] <- 99
mtcars2[2,1] <- 0
mtcars2[6,8] <- -99
(chg2 <- which_changed(mtcars1, mtcars2))
## Data differs in 3 places
p2 <- make_patch_code(mtcars1, mtcars2)
cat(p2, "\n")
## mtcars1[2, 'mpg'] <- 0
## mtcars1[3, 'hp'] <- 99
## mtcars1[6, 'vs'] <- -99
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment