-2

I am trying to compare vector a of objects using Reduce

  • all.equal does not work
  • == works for numericals but will not be sufficient for objects.

I would prefer a solution that does not use existing packages but R core functions only

Example (Simplified to use numeric vectors instead of objects):

test <- c(1,1,1,1,1)

Reduce("==",test)

[1] TRUE

I do not understand why == works while all.equal does not

Reduce(all.equal,test)

[1] "Modes: character, numeric"              
[2] "Lengths: 3, 1"                          
[3] "target is character, current is numeric"

Final remark:

This is not a duplicate. I am interested in a solution that compares objects not numeric values

Comparison of the elements of a vector of numeric values: See existing solution on stackoverflow Test for equality among all elements of a single numeric vector

scs
  • 567
  • 6
  • 22
  • The problem with `==` is that `1 == TRUE` evals as `TRUE`, but `all.equal(1, TRUE)` doesn't. If you run `Reduce(all.equal, test)` firstly it'll run all.equal(1, 1), which is TRUE; secondly, all.equal(1, TRUE), which results in a character, and so on. Have a look at this code for more details: `Reduce(all.equal, test, accumulate = TRUE)`. – Leonardo Hansa Oct 05 '21 at 09:39
  • Your example of `c(1,1,1)` just works because of `1 == TRUE` – danlooo Oct 05 '21 at 09:46

2 Answers2

3

You can try identical in sapply and compare each with the first element.

x <- list(list(1), list(1))
all(sapply(x[-1], identical, x[[1]]))
#[1] TRUE

x <- list(list(1), list(2))
all(sapply(x[-1], identical, x[[1]]))
#[1] FALSE
GKi
  • 37,245
  • 2
  • 26
  • 48
  • This solution ist more than 20 times faster than danloos solution for lists of large objects. Therefore this is the accepted answer – scs Oct 05 '21 at 10:47
0

Here is a function returning TRUE if all pairwise comparisons of the elements inside a list were identical:

all_pairs_equal <- function(elements) {
    all(mapply(function(x, y) identical(elements[x], elements[y]), 1, seq(1, length(elements))))
}

all_pairs_equal(list(iris, iris, iris))
#> [1] TRUE
all_pairs_equal(list(1, 1, 1))
#> [1] TRUE
all_pairs_equal(list(iris, iris, 2))
#> [1] FALSE

Created on 2021-10-05 by the reprex package (v2.0.1)

danlooo
  • 10,067
  • 2
  • 8
  • 22
  • I think there is no need to compare each with each other. If all are equal it must be enough to test of all are equal to the first. – GKi Oct 05 '21 at 09:47
  • Thats true, I revised my answer – danlooo Oct 05 '21 at 09:47
  • Now its not much difference to `all(sapply(x, identical, x[[1]]))` – GKi Oct 05 '21 at 09:48
  • Yes, but we can start at the second element because the reference element is always identical to itself – danlooo Oct 05 '21 at 09:52
  • 1
    Yes but then it needs to be tested if there is a second element for the case there is only one element... – GKi Oct 05 '21 at 09:55
  • This solution has a good coding style and works as far as I can test it. Therefore upvote. Faster solution of GKi gets the accepted answer – scs Oct 05 '21 at 10:48