2

I have a nested named list which looks like the following:

> data <- list("1"=list(rating=-1,points=190,name="Fernando"),"2"=list(rating=3,points=532,name="Carlos")) 
> data
$'1'
$'1'$rating
[1] -1

$'1'$points
[1] 190

$'1'$name
[1] "Fernando"

$'2'
$'2'$rating
[1] 3

$'2'$points
[1] 532

$'2'$name
[1] "Carlos"

Now when I use the melt function on "data" then it converts the value for name to numeric instead of character. And I can understand why because the data type for value is set to be numeric. Is there a way to convert the data type for value to be character overall.

Here's what I get when I use melt function:

> melt(data)
     value    L2     L1
1    -1      rating   1
2    190     points   1
3     1      name     1
4     3      rating   2
5    532     points   2
6     1      name     2

But what I want is the following:

     value    L2     L1
1    -1      rating   1
2    190     points   1
3   Fernando name     1
4     3      rating   2
5    532     points   2
6   Carlos   name     2  

where the data type of values is characters.

A Gore
  • 1,870
  • 2
  • 15
  • 26
  • seems like `"Fernando"` is stored as a `factor` variable. Otherwise `R` has no way of converting it to a number. – MichaelChirico Aug 06 '15 at 19:26
  • If `"Fernando"` is stored as a `character`, I imagine `melt` will convert everything to a `character`. – MichaelChirico Aug 06 '15 at 19:27
  • 4
    This is the dreaded `stringsAsFactors = TRUE`. The "incorrect" conversion actually happens in `rbind.fill`, after each singleton list element is converted to a data frame in `melt.default` using just a regular `data.frame()` call. If I run the code with `options(stringsAsFactors = FALSE)` you get what you want. – joran Aug 06 '15 at 19:29
  • @joran wow, that is so useful, I didn't know you could just specify in options like that. – Rorschach Aug 06 '15 at 19:34
  • @joran Thanks, it works! I thought there would be option/argument that I can pass to the function but your way works. Though I did try to pass `melt(data,stringsAsFactors=FALSE)` but it doesn't work. – A Gore Aug 06 '15 at 19:35
  • @nongkrong Well, I should note that routinely running R with `options(stringsAsFactors = FALSE)` is widely frowned upon since it is not the default setting it can lead to very surprising and hard to find bugs when sharing code with other people (like precisely this one!). I wasn't so much recommending that as a solution as offering it as proof of my explanation of the cause. – joran Aug 06 '15 at 19:36

2 Answers2

5

You could use rapply, not sure about your nestedness

melt(rapply(data, as.character, how="list"))
#      value     L2 L1
# 1       -1 rating  1
# 2      190 points  1
# 3 Fernando   name  1
# 4        3 rating  2
# 5      532 points  2
# 6   Carlos   name  2

This is the recursive version of apply, so it is useful for traversing nested lists.

Rorschach
  • 31,301
  • 5
  • 78
  • 129
2

I think that this should work; a nested lapply for the data object and then (after conversion to as.character) use melt of the reshape2 package.

 melt(lapply(data, function(x) lapply(x, as.character)))
     value     L2 L1
1       -1 rating  1
2      190 points  1
3 Fernando   name  1
4        3 rating  2
5      532 points  2
6   Carlos   name  2

or just in two steps with data <- lapply(data, function(x) lapply(x, as.character)) and then melt(data).

SabDeM
  • 7,050
  • 2
  • 25
  • 38