Search code examples
rvector

Reorder vector by index (also including all non-specified indices)


I would like to select certain elements (by index) from a vector in R. However, I would like the resultant vector also to contain the remaining elements that I did not specify at its end (i.e. the output should be the same length as the input vector, and each element should be returned once and once only). The input vector could be any length.

Essentially, I'm looking for something like the selection process in dplyr:

df %>%
    select(col1, col2, everything())

where everything() ensures the columns not specified are still returned to the right of the specified columns in the output dataframe.

Example

Supposing I want to pick the 2nd and 4th elements from each of the below vectors

Vector1 <- c("apple", "pear", "peach", "plum", "orange")
Vector2 <- c("lettuce", "carrot", "broccoli", "peas", "onion", "kale", "courgette")

The expected output would be:

  • From vector 1: "pear" "plum" "apple" "peach" "orange"

  • From vector 2: "carrot" "peas" "lettuce" "broccoli" "onion" "kale" "courgette"

Possible solution

The following method works, but it's a little long-winded. For Vector1, the code would be:

Vector1[c(2, 4, setdiff(1:length(Vector1), c(2, 4)))]

which gives the expected output specified above:

Putting this into a function:

move_elements_to_start_of_vector <- function(vector, element_indices_for_start){

        element_indices_for_end <- setdiff(1:length(vector), element_indices_for_start)
        order_of_elements <- c(element_indices_for_start, element_indices_for_end)

        return(vector[order_of_elements])

}

Checking it works:

move_elements_to_start_of_vector(Vector2, c(2, 4)) 

also gives the expected output.

Is there a simpler function to achieve the same results already existing in base R or a common library?


Solution

  • move2front <- \(x, idx) c(x[idx], x[-idx]) 
    
    Vector1 <- c("apple", "pear", "peach", "plum", "orange")
    Vector2 <- c("lettuce", "carrot", "broccoli", "peas", "onion", "kale", "courgette")
    
    move2front(Vector1, c(2, 4))
    # [1] "pear"   "plum"   "apple"  "peach"  "orange"
    
    move2front(Vector2, c(2, 3))
    # [1] "carrot"    "broccoli"  "lettuce"   "peas"      "onion"     "kale"     
    # [7] "courgette"
    

    You can extract the elements by index as you normally would with [c(2,4)]. Then you can remove them, which will preserve the order of the remaining elements with [-c(2,4)].

    Combine these two vectors into one using c().