Supposing I have a variable
x <- c(1,3,5,7,8)
Now x is in increasing order
How to check whether a variable is in increasing order in R?
From ?is.unsorted:
Test if an object is not sorted (in increasing order) ...
So, in this case, you could:
is.sorted = Negate(is.unsorted)
is.sorted(x)
#[1] TRUE
#> is.sorted(1:5)
#[1] TRUE
#> is.sorted(5:1)
#[1] FALSE
#> is.sorted(sample(5))
#[1] FALSE
#> is.sorted(sort(runif(5)))
#[1] TRUE
#> is.sorted(c(1,2,2,3))
#[1] TRUE
#> is.sorted(c(1,2,2,3), strictly = T)
#[1] FALSE
This function is fast, because it loops over the vector and breaks the loop as soon as an element is not ">=" (or ">", if "strictly = T") from the previous one.
Try this:
all(diff(x) > 0)
or
all(diff(x) >= 0)
I agree with #flodel that is.unsorted (h/t #alexis_laz) is probably even better.
Look at the differences:
R> x <- c(1,3,5,7,8)
R> allIncreasing <- function(x) all(diff(x)>0)
R> allIncreasing(x)
[1] TRUE
R> y <- x; y[3] <-0
R> allIncreasing(y)
[1] FALSE
R>
Related
I want to check if all elements in a list are named. I've came up with this solution, but I wanted to know if there is a more elegant way to check this.
x <- list(a = 1, b = 2)
y <- list(1, b = 2)
z <- list (1, 2)
any(stringr::str_length(methods::allNames(x)) == 0L) # FALSE, all elements are
# named.
any(stringr::str_length(methods::allNames(y)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
any(stringr::str_length(methods::allNames(z)) == 0L) # TRUE, at least one
# element is not named.
# Throw an error here.
I am not sure if the following base R code works for your general cases, but it seems work for the ones in your post.
Define a function f to check the names
f <- function(lst) length(lst) == sum(names(lst) != "",na.rm = TRUE)
and you will see
> f(x)
[1] TRUE
> f(y)
[1] FALSE
> f(z)
[1] FALSE
We can create a function to check if the the names attribute is NULL or (|) there is blank ("") name, negate (!)
f1 <- function(lst1) is.list(lst1) && !(is.null(names(lst1))| '' %in% names(lst1))
-checking
f1(x)
#[1] TRUE
f1(y)
#[1] FALSE
f1(z)
#[1] FALSE
Or with allNames
f2 <- function(lst1) is.list(lst1) && !("" %in% allNames(lst1))
-checking
f2(x)
#[1] TRUE
f2(y)
#[1] FALSE
f2(z)
#[1] FALSE
I have always heard that identical() is "safer" than ==. But playing around with them both it seems like the desired result is obtained by the latter and not the former. I'm assuming this has something to do with the attributes of the object generated by nrow() but it would be nice with a clarification as to why this happens in the example below:
> identical(3653510+2751069, 6404579)
[1] TRUE
> identical((3653510+nrow(df)), nrow(df2))
[1] FALSE
> nrow(df)
[1] 2751069
> nrow(df2)
[1] 6404579
> nrow(df2)-nrow(df)
[1] 3653510
> (3653510+nrow(df))==nrow(df2)
[1] TRUE
So to summarize, I have two questions:
What's going on with identical()?
What do we mean be saying a function is "safer" to use in this context?
It could be an attribute difference. e.g.
n1 <- 2751069
n2 <- 6404579
identical((3653510 + n1), n2)
#[1] TRUE
Both are numeric class. If we change one of them to integer, it returns FALSE
n2 <- 6404579L
identical((3653510 + n1), n2)
#[1] FALSE
With all.equal, we can also specify check.attributes = FALSE
all.equal((3653510 + n1), n2, check.attributes = FALSE)
#[1] TRUE
I'm looking for a function or operation such that if I have
A <- c(1, 2, 3, 4, 5)
and
B <- c(1, 2, 3)
and C <- c(2, 1)
I'd get a TRUE when checking whether A contained B, and FALSE when checking whether A contained C
basically, the equivalent of the %in% operator but that actually cares about the order of elements
In a perfect world, I'd be able to do this without some kind of apply statement, but I may end up having to
Well, if one's allowd to use a kind-of apply loop, then this could work:
"%seq_in%" = function(b,a) any(sapply(1:(length(a)-length(b)+1),function(i) all(a[i:(i+length(b)-1)]==b)))
(edited thanks to bug-finding by John Coleman!)
EDIT 2:
I couldn't resist trying to solve the 'non-contiguous' case, too:
# find_subseq() returns positions within vec of ordered elements of x, or stops with NA upon failing
find_subseq = function(x,vec) {
p=match(x[1],vec)
if(is.na(p)||length(x)==1){ p }
else { c(p,p+find_subseq(x[-1],vec[-seq_len(p)])) }
}
"%seq_somewhere_in%" = function(b,a) all(!is.na(find_subseq(b,a)))
Examples:
1:3 %seq_in% 1:10
[1] TRUE
c(3,1,2) %seq_in% 1:10
[1] FALSE
c(1,2,3) %seq_in% c(3,2,1,2,3)
[1] TRUE
2:1 %seq_in% c(1,2,1)
[1] TRUE
1:3 %seq_somewhere_in% c(1,10,10,2,10,10,10,3,10)
[1] TRUE
Maybe you can define a custom function subseq_check like below
subseq_check <- function(x,y) grepl(toString(y),toString(x),fixed = TRUE)
which gives
> subseq_check(A,B)
[1] TRUE
> subseq_check(A,C)
[1] FALSE
A Hard-core approach
subseq_find <- function(x,y) {
inds <- which(x == head(y,1))
if (length(inds)==0) return(FALSE)
any(sapply(inds, function(k) all(x[k:(k+length(y)-1)]==y)))
}
such that
> subseq_find(A,B)
[1] TRUE
> subseq_find(A,C)
[1] FALSE
I am looking for a function that verifies if a number is between two other numbers. I also need to control if I want a strict comparison (a
I know the function between() in dplyr. Yet, I have to know the upper and lower numbers.
MyNumber = 8
First = 2
Second = 10
# This will return TRUE
between(MyNumber, lower = First, upper = Second)
# But this will return FALSE
between(MyNumber, lower = Second, upper = First)
# This will return TRUE. I want it to return FALSE
First = 8
between(MyNumber, lower = First, upper = Second)
I need a function that returns TRUE no matter what is the order.
Something like:
between2 <- function(number,bounds) { number > min(bounds) & number < max(bounds)}
between2(8, c(2,10))
[1] TRUE
between2(8, c(10,2))
[1] TRUE
This function also deals with your added condition
between2(8,c(8,10))
[1] FALSE
You could do it with a simple arithmetics:
between <- function(number, first, second) { (first - number) * (second - number) < 0 }
Here are some example outputs:
> between(8, 2, 10)
[1] TRUE
> between(8, 10, 2)
[1] TRUE
> between(8, 10, 12)
[1] FALSE
> between(8, 1, 2)
[1] FALSE
You could use %in% with the : function, once you now first and last:
first <- 2
last <- 10
number <- 8
number %in% first:last
[1] TRUE
first <- 10
last <- 2
number <- 8
number %in% first:last
[1] TRUE
first <- 10
last <- 12
number <- 8
number %in% first:last
[1] FALSE
first <- 12
last <- 10
number <- 8
number %in% first:last
[1] FALSE
In a function, and strict lets you consider or not strict comparison:
my_between <- function(n, f, l, strict = FALSE) {
if (!strict) {
n %in% f:l # if strict == FALSE (default)
} else {
n %in% (f+1):(l-1) # if strict == TRUE
}
}
my_between(8, 2, 10)
What's wrong with
f_between <- function (num, L, R) num>=min(L,R) & num<=max(L,R)
f_between(8, 2, 10)
#[1] TRUE
f_between(6, 6, 10)
#[1] TRUE
f_between(2, -10, -2)
#[1] FALSE
f_between(3, 5, 7)
#[1] FALSE
This question already has answers here:
Check which elements of a vector is between the elements of another one in R
(4 answers)
Closed 9 years ago.
I have two vectors. I want to check the first element of first vector is between first and second element of second vector , then check the second element of first vector is between the third and forth element of the second vector ,.....How can I do this in R?
For example, If we have tow vectors
a = c(1.5, 2, 3.5)
b = c(1, 2, 3, 5, 3, 8)
the final result in R should be for 1.5 is TRUE and 3.5 is TRUE and for 2 is FALSE.
x <- c(1.5,3.5,3.5,3.5,4)
y <- 1:5
x > y & x < c(y[-1],NA)
#[1] TRUE FALSE TRUE FALSE FALSE
You need to take care of vector lengths and think about, what you want the result to be for the last element of x and of course.
More robust solution:
x <- c(1.5,3.5,3.5,3.5,4)
findInterval(x,y) == seq_along(x)
#[1] TRUE FALSE TRUE FALSE FALSE
x1 <- c(1.5,3.5)
findInterval(x1,y) == seq_along(x1)
#[1] TRUE FALSE
x2 <- c(1.5,3.5,1:5+0.5)
findInterval(x2,y) == seq_along(x2)
#[1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE
Here's one way.
s <- seq_along(a)
b[s] < a[s] & a[s] < b[s+1]
# [1] TRUE FALSE TRUE
Maybe this is not an ideal and fastest solution, but it works.
a <- rnorm(99)
b <- rnorm(100)
m <- cbind(b[-length(b)], b[-1])
a > m[,1] & a < m[,2]
You should check the lengths of both initial vectors.
Here is one-line solution:
sapply(1:length(a), function(i) {a[i] > b[i] & a[i] < b[i+1]})