Skip to content

Documentation: Add example with melt/unmelt that has list elements without names #12

@mpettis

Description

@mpettis

When we have lists that have some sub-lists that are unnamed, the melt/unmelt process will introduce names to those originally unnamed sub-lists. I propose that this example be added to documentation to show how those names can be removed, provided that the other named elements are character strings that cannot be parsed as integers. Here is the stackoverflow question where I asked about a related question and answered this one (@JorisChau actually provided the answer to the original question I had).

Stackoverflow answer: https://stackoverflow.com/a/76121308/1022967

Code example to be included with documentation/vignette/article?

#;; Melt and unmelt, remove names that arise from list positions in the original.
library(rrapply)

# Note: second level does not have names, just positions
lst <- list(A=list(list(A1A=2,A1B=3)
                   , list(A2A=2,A2B=3)))
str(lst)
#> List of 1
#>  $ A:List of 2
#>   ..$ :List of 2
#>   .. ..$ A1A: num 2
#>   .. ..$ A1B: num 3
#>   ..$ :List of 2
#>   .. ..$ A2A: num 2
#>   .. ..$ A2B: num 3

# Melting to dataframe
melt_df <-
    rrapply(lst, how="melt")
melt_df
#>   L1 L2  L3 value
#> 1  A  1 A1A     2
#> 2  A  1 A1B     3
#> 3  A  2 A2A     2
#> 4  A  2 A2B     3

# Unmelt back to list, but now the second level has names that are character
# strings of their integer position.  Compare to original list.
unmelt_lst <-
    rrapply(melt_df, how="unmelt")
str(unmelt_lst)
#> List of 1
#>  $ A:List of 2
#>   ..$ 1:List of 2
#>   .. ..$ A1A: num 2
#>   .. ..$ A1B: num 3
#>   ..$ 2:List of 2
#>   .. ..$ A2A: num 2
#>   .. ..$ A2B: num 3

# Here is how we can remove those second level names that were just from their
# positions.  Note: this assumes that there are no other names in this list that
# are pure character versions of an integer.

isParseableInteger <- function(x) {
    # False if null or na
    if (is.null(x) || is.na(x)) return(FALSE)
    
    # Check if they are numeric, return if it is equal to its integer form.
    if (is.numeric(x)) return(x == as.integer(x))
    
    # Cast to integer, check if it is not NA
    !is.na(suppressWarnings(as.integer(x)))
}

rrapply(
    unmelt_lst, 
    condition = \(x, .xname) {isParseableInteger(.xname)},
    f = \(x) {NULL},
    how = "names") |>
    str()
#> List of 1
#>  $ A:List of 2
#>   ..$ :List of 2
#>   .. ..$ A1A: num 2
#>   .. ..$ A1B: num 3
#>   ..$ :List of 2
#>   .. ..$ A2A: num 2
#>   .. ..$ A2B: num 3

Created on 2023-04-27 with reprex v2.0.2

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationenhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions