nachocab
nachocab

Reputation: 14454

How to split a vector into unequal chunks in R based on a condition?

Let's say I have these two vectors:

x <- c(1,2,4,6,7)
y <- c(3,7)

How can I split x into the elements that are smaller than each element of y? For example: c(1,2) | c(4,6,7). .

I guess one option would be to do a double loop and return the smallest element in y that is smaller than the current one in x: c(3,3,3,7,7). I could then split using this vector.

j <- 1
sapply(x, function(i){
  if (i <= y[j]) {
    y[j]
  } else {
    if (j < length(y)){
      j <- j + 1
    }
    y[j]
  }
})

I feel like there's a cleverer way to do this, but I can't figure it out.

Upvotes: 2

Views: 1569

Answers (4)

989
989

Reputation: 12935

Using cut and split in base R:

lapply(y, function(a) split(x, cut(x, c(-Inf, a, Inf))))

# [[1]]
# [[1]]$`(-Inf,3]`
# [1] 1 2

# [[1]]$`(3, Inf]`
# [1] 4 6 7


# [[2]]
# [[2]]$`(-Inf,7]`
# [1] 1 2 4 6 7

# [[2]]$`(7, Inf]`
# numeric(0)

Upvotes: 2

Karlan
Karlan

Reputation: 353

maybe not the best solution but it is quicker:

z <- x < min(y)

end <- x[z]

Upvotes: 0

Charles
Charles

Reputation: 150

Here is how I would do it:

x <- c(1,2,4,6,7)
y <- c(3,7)
out <- list(x[x < min(y)], x[!x < min(y)])

Here is the result:

> out
[[1]]
[1] 1 2

[[2]]
[1] 4 6 7

Upvotes: 4

lmo
lmo

Reputation: 38520

Here is a base R method using split and findInterval:

split(x, findInterval(x, y, rightmost.closed=TRUE))

$`0`
[1] 1 2

$`1`
[1] 4 6 7

The findInterval function returns a vector that categorizes the variable values in x along your criteria in y. The split function separates the vector as desired and returns a named list.

Upvotes: 4

Related Questions