简体   繁体   中英

How to index character vector in file.path in R

If I do:

file.path("", "a", "b", "c.txt")
[1] "/a/b/c.txt"

I got the correct file path, but if I do this way:

cc<-c("", "a", "b", "c.txt")
file.path(cc)
[1] ""      "a"     "b"     "c.txt"

It seems incorrect. I am wondering how to index cc in file.path() ?

I guess you could call this a list of arguments rather than just a single one. For example, you can access each element of the dots:

f <- function(...) {
  list(one = ..1,
       three = ..3,
       four = ..4,
       two = ..2)
}
f(1, 2, 3, 4)

# $one
# [1] 1
# 
# $three
# [1] 3
# 
# $four
# [1] 4
# 
# $two
# [1] 2

But what you really want to do is pass each as individual arguments. So in this case, you need to either do that explicitly (lots of typing) or use do.call which allows you to pass a list of parameters to functions

cc <- c("", "a", "b", "c.txt")
do.call('file.path', as.list(cc))
# [1] "/a/b/c.txt"

file.path is nice in that it only has two arguments, one of which you don't need to change but if you did you could do

do.call('file.path', c(as.list(cc), fsep = '/xx/'))
# [1] "/xx/a/xx/b/xx/c.txt"

so in this case you need to pass a named list to the function to match each argument

A side note which I have come across, something like

do.call('base::mean', list(1:4))
# Error in do.call("base::mean", list(1:4)) : 
#   could not find function "base::mean"

won't work if you need to specify a function in a particular package. You either need to do

f <- base:::mean; do.call('f', list(1:4))
# [1] 2.5

or just

do.call(base::mean, list(1:4))
# [1] 2.5

I was about to post the same as rawr's accepted answer/comment (so decided to add a bit more after waiting for him to post an answer and then giving up waiting although I see he now does have an answer):

do.call('file.path', as.list(cc))

Learning to use as.list and do.call was one of those lessons I learned several years down the road to my current perpetual intermediate R mastery. The reason that rawr's answer works is that the arguments to file.path need to come to the args component of the function as a list. The reason that simply wrapping them with list() , eg file.path(list(cc)) , fails is that the result is a list of length one, whereas the as.list function creates a list of length-4. The reason using file.path(as.list(cc)) also fails is that the parser still loops over that argument as a single vector.

Sometimes do.call is the only way to build a function call when the argument values are going to be supplied to a ... (dots) component of a function but exist in some other data-object. If passing to a function with named arguments one can use either lists or pairlists:

> dd <- list(from=1, to=2)
> seq(dd)
[1] 1 2

You can use paste with collapse="/" instead. So with:

cc <- c("", "a", "b", "c.txt")

You get:

R> paste(cc, collapse="/")
[1] "/a/b/c.txt"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM