Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to index character vector in file.path in R

Tags:

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()?

like image 544
David Z Avatar asked Jul 23 '15 18:07

David Z


People also ask

How do you find the index of a vector in R?

Use the which() Function to Find the Index of an Element in R. The which() function returns a vector with the index (or indexes) of the element which matches the logical vector (in this case == ).

How do I get a list of files in a folder in R?

To list all files in a directory in R programming language we use list. files(). This function produces a list containing the names of files in the named directory. It returns a character vector containing the names of the files in the specified directories.

What is a character vector in R?

Character/string – each element in the vector is a string of one or more characters. Built in character vectors are letters and LETTERS which provide the 26 lower (and upper) case letters, respecitively. > y = c("a", "bc", "def") > length(y)


3 Answers

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
like image 123
rawr Avatar answered Oct 23 '22 00:10

rawr


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(), e.g 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
like image 43
IRTFM Avatar answered Oct 23 '22 00:10

IRTFM


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"
like image 3
maccruiskeen Avatar answered Oct 22 '22 23:10

maccruiskeen