Test for equality among all elements of one vector

I am trying to check if all elements of a vector are equal to each other. The solutions I came up with seem a bit workaround, including length() checking.

 x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE y <- rep(2, times = 7) # TRUE 

With unique() :

 length(unique(x)) == 1 length(unique(y)) == 1 

With rle() :

 length(rle(x)$values) == 1 length(rle(y)$values) == 1 

A solution that would allow me to include the tolerance value for evaluating "equality" among the elements would be ideal to avoid FAQ 7.31 .

Is there a built-in function for the type of test that I completely ignored? identical() and all.equal() compare two R objects, so they will not work here.

Change 1

Here are some benchmarking results. Using the code:

 library(rbenchmark) John <- function() all( abs(x - mean(x)) < .Machine$double.eps ^ 0.5 ) DWin <- function() {diff(range(x)) < .Machine$double.eps ^ 0.5} zero_range <- function() { if (length(x) == 1) return(TRUE) x <- range(x) / mean(x) isTRUE(all.equal(x[1], x[2], tolerance = .Machine$double.eps ^ 0.5)) } x <- runif(500000); benchmark(John(), DWin(), zero_range(), columns=c("test", "replications", "elapsed", "relative"), order="relative", replications = 10000) 

With the results:

  test replications elapsed relative 2 DWin() 10000 109.415 1.000000 3 zero_range() 10000 126.912 1.159914 1 John() 10000 208.463 1.905251 

It looks like diff(range(x)) < .Machine$double.eps ^ 0.5 is the fastest.

+64
equality vector r
Jan 20 2018-11-21T00:
source share
9 answers

I use this method, which compares min and max, after dividing by the average:

 # Determine if range of vector is FP 0. zero_range <- function(x, tol = .Machine$double.eps ^ 0.5) { if (length(x) == 1) return(TRUE) x <- range(x) / mean(x) isTRUE(all.equal(x[1], x[2], tolerance = tol)) } 

If you are more serious about this, you probably want to remove the missing values ​​before calculating the range and value.

+24
Jan 20 2018-11-21T00:
source share

If these are all numerical values, then if tol is your tolerance, then ...

 all( abs(y - mean(y)) < tol ) 

- a solution to your problem.

EDIT:

After looking at this and other answers, and comparing a few things, the following is twice as fast as the DWin answer.

 abs(max(x) - min(x)) < tol 

This is a bit surprisingly faster than diff(range(x)) , since diff should not differ much from - and abs with two numbers. The range query should optimize getting the minimum and maximum. Both diff and range are primitive functions. But the timing does not lie.

+29
Jan 20 '11 at 21:30
source share
 > isTRUE(all.equal( max(y) ,min(y)) ) [1] TRUE > isTRUE(all.equal( max(x) ,min(x)) ) [1] FALSE 

Another on the same lines:

 > diff(range(x)) < .Machine$double.eps ^ 0.5 [1] FALSE > diff(range(y)) < .Machine$double.eps ^ 0.5 [1] TRUE 
+18
Jan 20 2018-11-21T00:
source share

Why not just use variance:

 var(x) == 0 

If all elements of x are equal, you get a variance of 0 .

+17
Mar 09 '16 at 18:32
source share

You can use identical() and all.equal() , comparing the first element with all the others, effectively looking at the comparison through:

 R> compare <- function(v) all(sapply( as.list(v[-1]), + FUN=function(z) {identical(z, v[1])})) R> compare(x) [1] FALSE R> compare(y) [1] TRUE R> 

This way you can add any epsilon to identical() as needed.

+10
Jan 20 2018-11-21T00:
source share

Since I am returning to this question again and again, here is an Rcpp solution that will usually be much faster than any of the R solutions if the answer is really FALSE (because it will stop the moment it encounters a mismatch) and will have that same speed as the fastest solution R if the answer is TRUE . For example, for the OP reference, system.time synchronizes to the nearest 0 using this function.

 library(inline) library(Rcpp) fast_equal = cxxfunction(signature(x = 'numeric', y = 'numeric'), ' NumericVector var(x); double precision = as<double>(y); for (int i = 0, size = var.size(); i < size; ++i) { if (var[i] - var[0] > precision || var[0] - var[i] > precision) return Rcpp::wrap(false); } return Rcpp::wrap(true); ', plugin = 'Rcpp') fast_equal(c(1,2,3), 0.1) #[1] FALSE fast_equal(c(1,2,3), 2) #[2] TRUE 
+9
Jul 19 '13 at 20:29
source share

I wrote a function specifically for this, which can check not only the elements in the vector, but also check whether all the elements in the list are identical . Of course, it also processes symbol vectors and all other types of vectors. It also has appropriate error handling.

 all_identical <- function(x) { if (length(x) == 1L) { warning("'x' has a length of only 1") return(TRUE) } else if (length(x) == 0L) { warning("'x' has a length of 0") return(logical(0)) } else { TF <- vapply(1:(length(x)-1), function(n) identical(x[[n]], x[[n+1]]), logical(1)) if (all(TF)) TRUE else FALSE } } 

Now try some examples.

 x <- c(1, 1, 1, NA, 1, 1, 1) all_identical(x) ## Return FALSE all_identical(x[-4]) ## Return TRUE y <- list(fac1 = factor(c("A", "B")), fac2 = factor(c("A", "B"), levels = c("B", "A")) ) all_identical(y) ## Return FALSE as fac1 and fac2 have different level order 
+5
Jul 10 '15 at
source share

In fact, you do not need to use min, mean or max. Based on John's answer:

 all(abs(x - x[[1]]) < tolerance) 
+2
Nov 03 '14 at 17:35
source share

It uses an alternative that uses the min, max trick, but for the data frame. In the example, I compare the columns, but the field parameter from apply can be changed to 1 for rows.

 valid = sum(!apply(your_dataframe, 2, function(x) diff(c(min(x), max(x)))) == 0) 

If valid == 0 , then all elements are the same

+2
Aug 13 '15 at 13:24
source share



All Articles