34

The question says it all - I want to take a list object full of data.frames and write each data.frame to a separate .csv file where the name of the .csv file corresponds to the name of the list object.

Here's a reproducible example and the code I've written thus far.

df <- data.frame(
    var1 = sample(1:10, 6, replace = TRUE)
    , var2 = sample(LETTERS[1:2], 6, replace = TRUE)
    , theday = c(1,1,2,2,3,3)
)

df.daily <- split(df, df$theday) #Split into separate days

lapply(df.daily, function(x){write.table(x, file = paste(names(x), ".csv", sep = ""), row.names = FALSE, sep = ",")})

And here is the top of the error message that R spits out

Error: Results must have one or more dimensions.
In addition: Warning messages:
1: In if (file == "") file <- stdout() else if (is.character(file)) { :
  the condition has length > 1 and only the first element will be used

What am I missing here?

3
  • Duplicate of stackoverflow.com/q/3411429/271616 Commented Nov 17, 2010 at 22:01
  • @Joshua - dar, Google search fail. I should go home now. Feel free to close this one. Commented Nov 17, 2010 at 22:03
  • It's not exactly a duplicate. Your error is telling that you are passing more than one string to write.table as a file name. names(x) returns all colnames of a data frame. Commented Nov 17, 2010 at 22:09

3 Answers 3

33

Try this:

sapply(names(df.daily), 
 function (x) write.table(df.daily[[x]], file=paste(x, "txt", sep=".") )   )

You should see the names ("1", "2", "3") spit out one by one, but the NULLs are the evidence that the side-effect of writing to disk files was done. (Edit: changed [] to [[]].)

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for base R solution and the more succinct way to use paste.
I think there should be df.daily[[x]].
Both df.daily[x] and df.daily[[x]] give the same result on my machine. I guess I can see the logic of your suspicion, though.
I think the reason that both forms succeed is that write.table coerces to data.frame class with as.data.frame() if the object is not one to start with and that will succeed if the object is a list with one dataframe.
For me result is not the same. Columns names in [] version have prefix (e.g. X1.var1), in [[]] version don't.
11

You could use mapply:

mapply(
  write.table,
  x=df.daily, file=paste(names(df.daily), "txt", sep="."),
  MoreArgs=list(row.names=FALSE, sep=",")
)

There is thread about similar problem on plyr mailing list.

Comments

7

A couple of things:

laply performs operations on a list. What you're looking for is d_ply. And you don't have to break it up by day, you can let plyr do that for you. Also, I would not use names(x) as that returns all of the column names of a data.frame.

d_ply(df, .(theday), function(x) write.csv(x, file=paste(x$theday,".csv",sep=""),row.names=F))

2 Comments

I always forget about the "_" plyr functions for some reason. This will do the trick. Thanks!
this solution doesn;t work for me. I get an error message as follows: Error in file(file, ifelse(append, "a", "w")) : invalid 'description' argument In addition: Warning message: In if (file == "") file <- stdout() else if (is.character(file)) { : the condition has length > 1 and only the first element will be used

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.