Moving columns within a data.frame() without retyping

Here is one way to do it:

> col_idx <- grep("g", names(df))
> df <- df[, c(col_idx, (1:ncol(df))[-col_idx])]
> names(df)
[1] "g" "a" "b" "c" "d" "e" "f"

I wrote this function recently called moveme. It's designed to work on vectors, with the intent of shuffling column orders around.

Here's the function:

moveme <- function (invec, movecommand) {
  movecommand <- lapply(strsplit(strsplit(movecommand, ";")[[1]], 
                                 ",|\\s+"), function(x) x[x != ""])
  movelist <- lapply(movecommand, function(x) {
    Where <- x[which(x %in% c("before", "after", "first", 
                              "last")):length(x)]
    ToMove <- setdiff(x, Where)
    list(ToMove, Where)
  })
  myVec <- invec
  for (i in seq_along(movelist)) {
    temp <- setdiff(myVec, movelist[[i]][[1]])
    A <- movelist[[i]][[2]][1]
    if (A %in% c("before", "after")) {
      ba <- movelist[[i]][[2]][2]
      if (A == "before") {
        after <- match(ba, temp) - 1
      }
      else if (A == "after") {
        after <- match(ba, temp)
      }
    }
    else if (A == "first") {
      after <- 0
    }
    else if (A == "last") {
      after <- length(myVec)
    }
    myVec <- append(temp, values = movelist[[i]][[1]], after = after)
  }
  myVec
}

Usage is simple. Try these out:

moveme(names(df), "g first")
moveme(names(df), "g first; a last; e before c")

Of course, using it to reorder the columns in your data.frame is straightforward:

df[moveme(names(df), "g first")]

And for data.tables (moves by reference, no copy) :

setcolorder(dt, moveme(names(dt), "g first"))

The basic options are:

  • first
  • last
  • before
  • after

Compounded moves are separated by a semicolon.


The subset function has a nice select argument that gives a convenient way to select ranges of columns by name:

df <- subset(df, select=c(g,a:f))

Use select from the dplyr package and its everything() function to move specific columns to the start or end of a data.frame.

Move to the beginning:

library(dplyr)
df %>%
  select(g, everything())

Move to the end:

df %>%
  select(-a, everything())

Or without the %>% pipe operator, those would be select(df, g, everything()) and select(df, -a, everything()) respectively.

Tags:

R