Reputation: 3174
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
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
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
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
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