Firstly, apologies that this is a long post - it's quite detailed and the difference between the result that I would like to achieve and the one I have been able to achieve is subtle but significant.
The core issue is that I want to make a recursive list in R, one in which the list elements increment upwards.
The core reason is that right now I am trying to write a script to automatically create a lookup table variable in Google Tag Manager via the GTM API.
The documentation for creating variables is here: https://developers.google.com/tag-manager/api/v2/reference/accounts/containers/workspaces/variables/create
The desired workflow is this:
- Pull mapping table from a Google Sheet using the
googlesheets
package - Convert relevant columns into list format
- Upload final version to GTM via the GTM API
The issue I am having at the moment is step 2, creating the list in the right way. I have figured out a way to reverse engineer the list that the GTM API provides, but the method involves manually adding each row from the values to be mapped as a new list, which makes no sense when you have variable row lengths (besides being a pain in the ass).
This is what a working end result looks like (this was made with the manual method); this is called post_body1
:
$name
[1] "test1"
$type
[1] "smm"
$parameter
$parameter[[1]]
$parameter[[1]]$type
[1] "boolean"
$parameter[[1]]$key
[1] "setDefaultValue"
$parameter[[1]]$value
[1] "true"
$parameter[[2]]
$parameter[[2]]$type
[1] "template"
$parameter[[2]]$key
[1] "input"
$parameter[[2]]$value
[1] "{{Event Name}}"
$parameter[[3]]
$parameter[[3]]$type
[1] "list"
$parameter[[3]]$key
[1] "map"
$parameter[[3]]$list
$parameter[[3]]$list[[1]]
$parameter[[3]]$list[[1]]$type
[1] "map"
$parameter[[3]]$list[[1]]$map
$parameter[[3]]$list[[1]]$map[[1]]
$parameter[[3]]$list[[1]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[1]]$map[[1]]$value
[1] "explosion"
$parameter[[3]]$list[[1]]$map[[2]]
$parameter[[3]]$list[[1]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[1]]$map[[2]]$value
[1] "volcano"
$parameter[[3]]$list[[2]]
$parameter[[3]]$list[[2]]$type
[1] "map"
$parameter[[3]]$list[[2]]$map
$parameter[[3]]$list[[2]]$map[[1]]
$parameter[[3]]$list[[2]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[2]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[2]]$map[[1]]$value
[1] "flood"
$parameter[[3]]$list[[2]]$map[[2]]
$parameter[[3]]$list[[2]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[2]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[2]]$map[[2]]$value
[1] "tsunami"
$parameter[[3]]$list[[3]]
$parameter[[3]]$list[[3]]$type
[1] "map"
$parameter[[3]]$list[[3]]$map
$parameter[[3]]$list[[3]]$map[[1]]
$parameter[[3]]$list[[3]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[3]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[3]]$map[[1]]$value
[1] "drought"
$parameter[[3]]$list[[3]]$map[[2]]
$parameter[[3]]$list[[3]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[3]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[3]]$map[[2]]$value
[1] "heatwave"
Here are some variables:
variable_name <- 'test1'
map_values <- tibble(key=c('explosion','flood','drought'),
value = c('volcano','tsunami','heatwave'))
var_code <- 'smm'
set_default <- TRUE
map_input <- 'Event Name'
And here's the code for creating the list above - as mentioned, this isn't a scalable solution.
post_body1 <- list(name = variable_name,
type = var_code,
parameter = list(
list(type = 'boolean',
key = 'setDefaultValue',
value = ifelse(set_default == TRUE,'true','false')),
list(type = 'template',
key = 'input',
value = paste('{{',map_input,'}}',sep='')),
list(type = 'list',
key = 'map',
list = list(list(
type = 'map',
map = list(list(
type = 'template',
key = 'key',
value = map_values$key[[1]]),
list(type = 'template',
key = 'value',
value = map_values$value[[1]])
)
),
list(type = 'map',
map = list(list(
type = 'template',
key = 'key',
value = map_values$key[[2]]),
list(type = 'template',
key = 'value',
value = map_values$value[[2]])
)
),
list(type = 'map',
map = list(list(
type = 'template',
key = 'key',
value = map_values$key[[3]]),
list(type = 'template',
key = 'value',
value = map_values$value[[3]])
)
)
)
)
)
)
So I tried to create a new solution that can handle the post_body1$parameter[[3]]$list
creation programmatically, and I have almost done it but not quite, and also I think it's not a very elegant solution, and there's probably a better way to create it using something like the purrr
package.
test_list <- list()
for (i in 1:nrow(map_values)) {
newlist <- list(
type = 'map',
map = list(list(
type = 'template',
key = 'key',
value = map_values$key[[i]]),
list(type = 'template',
key = 'value',
value = map_values$value[[i]])
)
)
test_list <- c(test_list,newlist)
}
post_body2 <- list(name = variable_name,
type = var_code,
parameter = list(
list(type = 'boolean',
key = 'setDefaultValue',
value = ifelse(set_default == TRUE,'true','false')),
list(type = 'template',
key = 'input',
value = paste('{{',map_input,'}}',sep='')),
list(type = 'list',
key = 'map',
list = list(test_list))
)
)
So this method produces something that is quite similar to the brute force method above, with one crucial difference: the index for post_body2$parameter[[3]]$list
does not increment in the same way as post_body1$parameter[[3]]$list
; here's what the post_body2$parameter[[3]]$list
looks like:
$parameter[[3]]$list
$parameter[[3]]$list[[1]]
$parameter[[3]]$list[[1]]$type
[1] "map"
$parameter[[3]]$list[[1]]$map
$parameter[[3]]$list[[1]]$map[[1]]
$parameter[[3]]$list[[1]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[1]]$map[[1]]$value
[1] "explosion"
$parameter[[3]]$list[[1]]$map[[2]]
$parameter[[3]]$list[[1]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[1]]$map[[2]]$value
[1] "volcano"
$parameter[[3]]$list[[1]]$type
[1] "map"
$parameter[[3]]$list[[1]]$map
$parameter[[3]]$list[[1]]$map[[1]]
$parameter[[3]]$list[[1]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[1]]$map[[1]]$value
[1] "flood"
$parameter[[3]]$list[[1]]$map[[2]]
$parameter[[3]]$list[[1]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[1]]$map[[2]]$value
[1] "tsunami"
$parameter[[3]]$list[[1]]$type
[1] "map"
$parameter[[3]]$list[[1]]$map
$parameter[[3]]$list[[1]]$map[[1]]
$parameter[[3]]$list[[1]]$map[[1]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[1]]$key
[1] "key"
$parameter[[3]]$list[[1]]$map[[1]]$value
[1] "drought"
$parameter[[3]]$list[[1]]$map[[2]]
$parameter[[3]]$list[[1]]$map[[2]]$type
[1] "template"
$parameter[[3]]$list[[1]]$map[[2]]$key
[1] "value"
$parameter[[3]]$list[[1]]$map[[2]]$value
[1] "heatwave"
If you are still reading, what is the method by which I can create this list in the desired format?
Edit: on the request of @muddy-cloudskipper I am adding the dput
for the desired output, which is this:
list(name = "test1", type = "smm", parameter = list(list(type = "boolean",
key = "setDefaultValue", value = "true"), list(type = "template",
key = "input", value = "{{Event Name}}"), list(type = "list",
key = "map", list = list(list(type = "map", map = list(list(
type = "template", key = "key", value = "explosion"),
list(type = "template", key = "value", value = "volcano"))),
list(type = "map", map = list(list(type = "template",
key = "key", value = "flood"), list(type = "template",
key = "value", value = "tsunami"))), list(type = "map",
map = list(list(type = "template", key = "key", value = "drought"),
list(type = "template", key = "value", value = "heatwave")))))))
What I want to create is a function that will lead to that output; it would be something like this, although this isn't quite right.
function (variable_name, var_code, set_default, map_input, map_values)
{
test_list <- list()
for (i in 1:nrow(map_values)) {
newlist <- list(type = "map", map = list(list(type = "template",
key = "key", value = map_values$key[[i]]), list(type = "template",
key = "value", value = map_values$value[[i]])))
test_list <- c(test_list, newlist)
}
post_body <- list(name = variable_name, type = var_code,
parameter = list(list(type = "boolean", key = "setDefaultValue",
value = ifelse(set_default == TRUE, "true", "false")),
list(type = "template", key = "input", value = paste("{{",
map_input, "}}", sep = "")), list(type = "list",
key = "map", list = list(test_list))))
return(post_body)
}