Dimon D.
Dimon D.

Reputation: 464

how to loop a vector comparing rows without FOR

I need some hints to make effective loop in vector but for “FOR…” loop because of optimization issues. At first glance, it is recommended to use such functions as apply(), sapply().

I have a vector converted into matrix:

x1<-c(1,2,4,1,4,3,5,3,1,0)

Looping through the vector I need to replace all x1[i+1]=x1[i] if x[i]>x[i+1]. Example: Input vector:

x1<-as.matrix(c(1,2,4,1,4,3,5,3,1,0))

Output vector:

c(1,2,4,4,4,4,5,5,5,5)

My approach is to use user function in apply() but I have some difficulties how to code correctly the relation of x[i] and x[i+1] in user function. I would be very grateful for your ideas or hints.

Upvotes: 0

Views: 119

Answers (2)

A. Webb
A. Webb

Reputation: 26446

In general you can use Reduce with accumulate=TRUE for cumulative operations

Reduce(max,x1,accumulate=TRUE)
# [1] 1 2 4 4 4 4 5 5 5 5

But as @Khashaa points out, the common cases cumsum,cumprod,cummin, and yours, cummax are provided as efficient base functions.

cummax(x1)
# [1] 1 2 4 4 4 4 5 5 5 5

Upvotes: 2

akrun
akrun

Reputation: 887038

We could do this using ave. (Using the vector x1)

 ave(x1,cumsum(c(TRUE,x1[-1]>x1[-length(x1)])), FUN=function(x) head(x,1))
 #[1] 1 2 4 4 4 4 5 5 5 5

We create a grouping variable based on the condition described in the OP's post. Check whether the succeeding element (x1[-1] - removed first element) is greater than the current element (x1[-length(x1)] -removed last element).

 x1[-1]>x1[-length(x1)]
 #[1]  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE

The length is one less than the length of the vector x1. So, we append TRUE to make the length equal and then do the cumsum

 cumsum(c(TRUE,x1[-1]>x1[-length(x1)]))
 #[1] 1 2 3 3 4 4 5 5 5 5

This we use as grouping variable in ave and select the first observation of 'x1' within each group


Another option would to get the logical index (c(TRUE, x1[-1] > x1[-length(x1)])) as before, negate it (!) so that TRUE becomes FALSE, and FALSE as TRUE, convert the TRUE values to 'NA' (NA^(!...)), and then use na.locf from library(zoo) to replace the NA values with the preceding non-NA value.

 library(zoo)
 na.locf(x1*NA^(!c(TRUE,x1[-1]>x1[-length(x1)])))
 #[1] 1 2 4 4 4 4 5 5 5 5

Upvotes: 2

Related Questions