3

Say I have a string such as "x = 1, y = 'cat', z = NULL". I want to obtain the list created by the code list(x = 1, z = 'cat', z = NULL). Here is my first attempt, which I am aware is horrible:

parse_text <- function(x) parse(text = x)[[1]]
strsplit2 <- function(x, ...) strsplit(x, ...)[[1]] 
trim_whitespace <- function (x) gsub("^\\s+|\\s+$", "", x)

# take 1

x <- "nk = 1, ncross = 1, pmethod = 'backward'"
x <- strsplit2(x, ",")
xs <- lapply(x, strsplit2, "=")
keys <- lapply(xs, function(x) trim_whitespace(x[1]))
vals <- lapply(xs, function(x) parse_text(x[2]))

setNames(vals, keys)

This is what I imagined a more canonical approach to look like:

# take 2

x <- "nk = 1, ncross = 1, pmethod = 'backward'"
x <- strsplit2(x, ",")
xs <- lapply(x, parse_text)

do.call(list, xs)

But this loses the names of the list. Any help much appreciated! Cheers

Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138
Mullefa
  • 1,237
  • 1
  • 15
  • 27

3 Answers3

6

You can first create a string containing the expression that you want to execute (i.e. list('your string'), in this case "list( nk = 1, ncross = 1, pmethod = 'backward' )" ) with function paste to add list( and ), then parse the expression with parse function and finally evaluate it with eval function:

x <- "nk = 1, ncross = 1, pmethod = 'backward'" #your string
eval(parse(text=paste('list(',x,')'))) #create and returns the desired list
$nk
[1] 1

$ncross
[1] 1

$pmethod
[1] "backward"

As shown, this will returns you the correct named list.

I hope this will help you.

WoDoSc
  • 2,598
  • 1
  • 13
  • 26
  • Thanks - this works, but still seems a little 'hacky' - is this fair or not?! I'd be interested to see if there are any more ways of achieving what I want... – Mullefa Jun 04 '14 at 13:31
  • Why do you say this is hacky? What and where in particular do you see hacky elements? Because I don't think you can find a lot of other ways to do this in a simpler manner without loss in clarity and avoiding even more hacky code. – WoDoSc Jun 04 '14 at 13:37
  • @Mullefa how else would you expect to do this. What you want to do is hacky. This is just the best solution for what you want to do. The other option is to split the string using a regexp, turn the values into a list, and name the list using `setNames`. This is easier. – Simon O'Hanlon Jun 04 '14 at 13:51
  • Sorry, no offense meant - I except that what I'm trying to do is hacky :-/ Talking to a colleague at work this seems like the best solution - any solutions which involve splitting by `,` run into problems with strings such as `"x = c(1,2,3), y = 2"` – Mullefa Jun 04 '14 at 17:23
0

Here is another way, avoiding the dreaded parse & eval route (but IMHO entirely suitable for this use-case). It relies on the conformity of your tag=value pairings, delimited by ,.

x <- "nk = 1, ncross = 1, pmethod = 'backward'"

# Split into tag=value
vals <- strsplit( x , "," )[[1]]

# Split again and transform to matrix of tags and values
mat <- do.call( rbind , strsplit( vals , "=" ) )

# Return as a list
setNames( as.list( mat[,2] ) , mat[,1] )

#$`nk `
#[1] " 1"

#$` ncross `
#[1] " 1"

#$` pmethod `
#[1] " 'backward'"
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
0

Convert the commas to semicolons, source the string into environment e and convert e to a list:

source(textConnection(chartr(",", ";", s)), local = e <- new.env())
as.list(e)

giving:

$x
[1] 1

$y
[1] "cat"

$z
NULL
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341