Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

insert elements in a vector in R

Tags:

r

I have a vector in R,

a = c(2,3,4,9,10,2,4,19)

let us say I want to efficiently insert the following vectors, b, and c,

b = c(2,1)
d = c(0,1)

right after the 3rd and 7th positions (the "4" entries), resulting in,

e = c(2,3,4,2,1,9,10,2,4,0,1,19)

How would I do this efficiently in R, without recursively using cbind or so.

I found a package R.basic but its not part of CRAN packages so I thought about using a supported version.

like image 958
user2805568 Avatar asked Sep 23 '13 03:09

user2805568


People also ask

How do you add elements to a vector?

To add elements to vector, you can use push_back() function. push_back() function adds the element at the end of this vector. Thus, it increases the size of vector by one.

Can you append to a vector?

Appending to a vector means adding one or more elements at the back of the vector. The C++ vector has member functions. The member functions that can be used for appending are: push_back(), insert() and emplace(). The official function to be used to append is push_back().

What does append () do in R?

append() function in R is used for merging vectors or adding more elements to a vector.


3 Answers

Try this:

result <- vector("list",5)
result[c(TRUE,FALSE)] <- split(a, cumsum(seq_along(a) %in% (c(3,7)+1)))
result[c(FALSE,TRUE)] <- list(b,d)
f <- unlist(result)

identical(f, e)
#[1] TRUE

EDIT: generalization to arbitrary number of insertions is straightforward:

insert.at <- function(a, pos, ...){
    dots <- list(...)
    stopifnot(length(dots)==length(pos))
    result <- vector("list",2*length(pos)+1)
    result[c(TRUE,FALSE)] <- split(a, cumsum(seq_along(a) %in% (pos+1)))
    result[c(FALSE,TRUE)] <- dots
    unlist(result)
}


> insert.at(a, c(3,7), b, d)
 [1]  2  3  4  2  1  9 10  2  4  0  1 19

> insert.at(1:10, c(4,7,9), 11, 12, 13)
 [1]  1  2  3  4 11  5  6  7 12  8  9 13 10

> insert.at(1:10, c(4,7,9), 11, 12)
Error: length(dots) == length(pos) is not TRUE

Note the bonus error checking if the number of positions and insertions do not match.

like image 100
Ferdinand.kraft Avatar answered Oct 16 '22 18:10

Ferdinand.kraft


You can use the following function,

ins(a, list(b, d), pos=c(3, 7))
# [1]  2  3  4  2  1  9 10  2  4  0  1  4 19

where:

ins <- function(a, to.insert=list(), pos=c()) {

  c(a[seq(pos[1])], 
    to.insert[[1]], 
    a[seq(pos[1]+1, pos[2])], 
    to.insert[[2]], 
    a[seq(pos[2], length(a))]
    )
}
like image 35
Ricardo Saporta Avatar answered Oct 16 '22 19:10

Ricardo Saporta


Here's another function, using Ricardo's syntax, Ferdinand's split and @Arun's interleaving trick from another question:

ins2 <- function(a,bs,pos){
    as <- split(a,cumsum(seq(a)%in%(pos+1)))
    idx <- order(c(seq_along(as),seq_along(bs)))
    unlist(c(as,bs)[idx])
}

The advantage is that this should extend to more insertions. However, it may produce weird output when passed invalid arguments, e.g., with any(pos > length(a)) or length(bs)!=length(pos).

You can change the last line to unname(unlist(... if you don't want a's items named.

like image 6
Frank Avatar answered Oct 16 '22 20:10

Frank