Reputation: 136
My test below doesn't work. Can anyone suggest a different approach?
===different contents, same structure, want "true" for comparison
> x<-c(1,2,3)
> y<-x
> identical(str(x),str(y))
num [1:3] 1 2 3
num [1:3] 1 2 3
[1] TRUE
> y[3]<-999
> identical(str(x),str(y))
num [1:3] 1 2 3
num [1:3] 1 2 999
[1] TRUE
> str(x)
num [1:3] 1 2 3
> str(y)
num [1:3] 1 2 999
>
but this approach is wrong because this says x and z have the same structure!
> z<-list("a","b")
> identical(str(x),str(z))
num [1:3] 1 2 3
List of 2
$ : chr "a"
$ : chr "b"
[1] TRUE
I'm trying this because I need a way to confirm that an R object I construct has exactly the same type as what is provided in R package examples.
Upvotes: 4
Views: 2274
Reputation: 577
We have a new option in the quiver now that goes by the name of Waldo and solves your problem in a more robust way. However, I still think you may want to code your own comparison function so you know what is going on.
> library('waldo')
> x <- c(1,2,3)
> y <- x
> compare(x, y)
✓ No differences
> y[3] <- 999
> compare(x, y)
`old`: 1 2 3
`new`: 1 2 999
Upvotes: 0
Reputation: 444
I am answering the version of this problem posed in a comment, namely how to test whether two objects have the same type, class, names and other attributes, although possibly different data. For example, you may want to confirm that two matrices have the same dimensions, and the same row and column names, and are of the same type.
SameStruc <- function(x, y) identical(`is.na<-`(x), `is.na<-`(y))
We can test this on two matrices:
M1 <- matrix(1:30, 3, 10, dimnames=list(LETTERS[1:3], letters[1:10]))
M2 <- M1
M2[1:30] <- 129:100
SameStruc(M1, M2) # TRUE
# M1 and M2 are both integer matrices, 3 x 10, with the same dimnames but different data
M3 <- M1
M3[3,5] <- 1 * M3[3,5]
all(M1 == M3) # TRUE (the numerical values of the contents of M1 and M3 are the same)
SameStruc(M1, M3) # FALSE (M3 has type "double" while M1 has type "integer")
I haven't tested this function on lists or dataframes or any objects other than matrices. I think it should work, though, with the proviso that on a list it will just test the outermost list structure, it does not test the structure of each pair of list elements.
Also I assume this function is highly inefficient for large objects because it creates a copy of each object filled with NAs.
Upvotes: 0
Reputation: 577
This answer is quite late, but may help visitors facing the same issue.
I need a way to confirm that an R object I construct has exactly the same type as [...]
For this specific case, consider typeof()
. However, this might not be what you want.
To check if the types of vectors in a data.frame match, have a look at sapply(df, typeof)
.
For a more general solution, I suggest building the check yourself, since for every use case, 'structure' can have a different meaning. Is it just about types? Would you like to differentiate between double
andinteger
? Or check for the names of a data.frame as well? Or its dimensions? What if everything is identical except for the levels of one factor?
Building it yourself has a big advantage: You know what is happening.
Other useful functions are dim()
, ncol()
, nrow()
, names()
, class()
, attributes()
and mode()
.
Upvotes: 0
Reputation: 101
Been a while since this question was asked, but I've been tackling a similar problem.
Came up with this function as a solution:
CompareStructure <-
function(x, y) {
# function to recursively compare a nested list of structure annotations
# using pairwise comparisons
TypeCompare <-
function(xSTR, ySTR) {
if (length(xSTR) == length(ySTR)) {
all(mapply(
xSTR,
ySTR,
FUN = function(xValue, yValue) {
if (is.list(xValue) && is.list(yValue)) {
all(TypeCompare(xValue, yValue))
} else if (is.list(xValue) == is.list(yValue)) {
identical(xValue, yValue)
} else {
FALSE
}
}
))
} else {
FALSE
}
}
# if both inputs are lists
if (is.list(x) && is.list(y)) {
# use Rapply to recursively apply function down list
xSTR <-
rapply(
x,
f = function(values) {
c(mode(values), length(values))
},
how = "list"
)
# use Rapply to recursively apply function down list
ySTR <-
rapply(
y,
f = function(values) {
c(mode(values), length(values))
},
how = "list"
)
# call the compare function on both structure annotations
return(TypeCompare(xSTR, ySTR))
} else {
# if inputs are not same class == automatic not same structure
if (class(x) != class(y)) {
FALSE
} else {
# get dimensions of the x input, if null get length
xSTR <-
if (is.null((dimsX <- dim(x)))) {
length(x)
} else {
dimsX
}
# get dimensions of the y input, if null get length
ySTR <-
if (is.null((dimsY <- dim(y)))) {
length(y)
} else {
dimsY
}
# call the compare function on both structure annotations
return(TypeCompare(xSTR, ySTR))
}
}
}
Compares the mode and length of elements in a nested list and classes and dimensions of no-list objects
Upvotes: 4
Reputation: 453
The function dput() is for structure.
x <- c(1, 2, 3)
y <- x
identical(dput(x), dput(y))
# c(1, 2, 3)
# c(1, 2, 3)
# [1] TRUE
z <- list("a", "b")
identical(dput(x), dput(z))
# c(1, 2, 3)
# list("a", "b")
# [1] FALSE
Upvotes: -2