Search code examples
rstringstrsplit

Splitting chain into data.frame with from and to fields


I have vectors looking like var a %->% var b %->% var c %->% var a. The %->% denotes arcs. I want to split those vectors in data.frames of the form:

   from    to
1 var a var b
2 var b var c
3 var c var a

I found two versions which both seem overlycomplicated.

Version 1: with a for loop. Does what I want but is fairly complicated

v <- "var a %->% var b %->% var c %->% var a"
v <- trimws(unlist(strsplit(v, "%->%")))
links <- data.frame(from = character(length(v) - 1), to = character(length(v) - 1), stringsAsFactors = FALSE)
for(i in 1:length(v) - 1) {
  links$from[i] <- v[i]
  links$to[i] <- v[i + 1]
}

Verison 2: I found a solution using sapply which removes the for-loop but the <<- is a bit dangerous I think:

sapply(1:(length(v) - 1), function(i) {links$from[i] <<- v[i]; links$to[i] <<- v[i + 1]})

Are there simpler options to achieve what I want?


Solution

  • You can assign the whole columns at once:

    v <- "var a %->% var b %->% var c %->% var a"
    v <- trimws(unlist(strsplit(v, "%->%")))
    
    data.frame(from = head(v, -1), to = tail(v, -1))
    #    from    to
    # 1 var a var b
    # 2 var b var c
    # 3 var c var a
    

    head(v, -1) is a nice way to write v[-length(v)] (all but the last element of v), and tail(v, -1) is the parallel way to write v[-1] (all but the first element of v). You can use the [ versions if they seem clearer to you:

    data.frame(from = v[-length(v)], to = v[-1])
    # same result