Создание рекурсивного списка в R с регулярно увеличивающимися индексами - PullRequest
0 голосов
/ 24 января 2019

Во-первых, извиняюсь, что это длинный пост - он довольно подробный, и разница между результатом, которого я хотел бы достичь, и результатом, которого я смог достичь, неуловима, но значительна.

Основная проблема заключается в том, что я хочу создать рекурсивный список в R, в котором элементы списка увеличиваются вверх.

Основная причина в том, что сейчас я пытаюсь написать скрипт для автоматического создания переменной таблицы поиска в Google Tag Manager через GTM API.

Документация по созданию переменных находится здесь: https://developers.google.com/tag-manager/api/v2/reference/accounts/containers/workspaces/variables/create

Требуемый рабочий процесс такой:

  1. Извлечь таблицу сопоставления из Google Sheet с помощью пакета googlesheets
  2. Преобразование соответствующих столбцов в формат списка
  3. Загрузка окончательной версии в GTM через GTM API

Проблема, с которой я сталкиваюсь в данный момент, - это шаг 2, создание списка правильным образом. Я нашел способ обратного инжиниринга списка, который предоставляет API GTM, но метод предполагает ручное добавление каждой строки из значений, которые должны отображаться в новый список, что не имеет смысла, когда у вас есть переменные длины строк (помимо того, что боль в заднице).

Вот так выглядит рабочий конечный результат (это было сделано ручным методом); это называется 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"

Вот некоторые переменные:

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'

А вот код для создания списка выше - как уже упоминалось, это не масштабируемое решение.

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]])
            )
          )
              )
                     )
)
)

Итак, я попытался создать новое решение, которое может обрабатывать создание post_body1$parameter[[3]]$list программно, и я почти сделал это, но не совсем, а также я думаю, что это не очень элегантное решение, и есть вероятно, лучший способ создать его, используя пакет типа purrr.

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))
)
)

Таким образом, этот метод производит нечто, очень похожее на метод грубой силы выше, с одним существенным отличием: индекс для post_body2$parameter[[3]]$list не увеличивается так же, как post_body1$parameter[[3]]$list; вот как выглядит post_body2$parameter[[3]]$list:

$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"

Если вы все еще читаете, каким способом я могу создать этот список в нужном формате?

Редактировать: по запросу @ muddy-cloudskipper я добавляю dput для желаемого результата, а именно:

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")))))))

Я хочу создать функцию, которая приведет к этому выводу; было бы что-то вроде этого, хотя это не совсем правильно.

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)
}

1 Ответ

0 голосов
/ 24 января 2019

Я думаю, что это должно сработать, я строю отдельно переменную часть списка, а затем склеиваю все вместе:

  sublist <- unname(Map(function(key,value) list(type = "map",
                                                 map=list(
    list(type="template",
         key ="key",
         value = key),
    list(type = "template",
         key = "value",
         value = value))), map_values$key, map_values$value))

  res <- list(name = variable_name,
              type = var_code,
              parameter = c(list(
                list(type = 'boolean',
                     key = 'setDefaultValue',
                     value = ifelse(set_default == TRUE,'true','false')),
                list(type = 'template',
                     key = 'input',
                     value = paste('{{',map_input,'}}',sep=''))),
                list(list(type = "list",
                     key = "map",
                     list=sublist))))

  identical(res,output)
  # [1] TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...