wush978
wush978

Reputation: 3174

Split vector by location

If there is a vector x with

length(x)
# 100

And there is a vector a, which denotes the leading index of subvector of x:

a
# 1, 5, 23, 79

Then I want to split x according to a as follow:

list(x[1:4], x[5:22], x[23:78], x[79:100])

Is there a quick way to do this in R?

Upvotes: 4

Views: 734

Answers (4)

akrun
akrun

Reputation: 886948

lapply(seq(a),function(i) x[a[i]:c(a[-1]-1,length(x))[i]])

Explanation of the code:

seq(a) #returns a index vector of length 4  

as.list(seq(a)) 

or

lapply(seq(a),function(i) i) #returns a list with the index elements (1:4)

lapply(seq(a),function(i) a[i])#returns the list with corresponding values of `a`
lapply(seq(a),function(i) c(a[-1]-1, length(x))[i]) #returns list with end points

Joining the above two lines of code:

lapply(seq(a),function(i) a[i]:c(a[-1]-1, length(x))[i]) # sequence of start:end points

lapply(seq(a),function(i) x[a[i]:c(a[-1]-1, length(x))[i]]) #returns the values of x between start:end index

Upvotes: 2

thelatemail
thelatemail

Reputation: 93813

Both the previous answers rely on making lists/vectors for splitting that are the same length as the original x vector. This might be inefficient in the instance of a very long vector and can be avoided:

Map(function(i,j) x[i:j], a, cumsum(diff(c(a, length(x)+1))))

Upvotes: 5

josliber
josliber

Reputation: 44309

This is a one-liner with rep and split:

split(x, rep(seq(a), diff(c(a, length(x)+1))))

seq(a) returns the numbers 1 through 4, and rep repeats them the proper number of times based on a (extracted using the diff function). Finally, split breaks up an object passed as the first parameter using categories passed as the second parameter.

Upvotes: 4

Ben Bolker
Ben Bolker

Reputation: 226097

Construct the list of index vectors, then lapply():

vec <- mapply(seq,a,length=diff(c(a,101)))
lapply(vec,function(v) x[v])

Upvotes: 1

Related Questions