Доступ к именованным элементам вложенного списка со строковым именем в R - PullRequest
3 голосов
/ 13 января 2020

Я пытаюсь найти способ доступа к именованным элементам вложенного списка, передавая их имена в виде строки (или списка строк). Нечто подобное вы можете сделать с attr(the_thing, "the_attr"), но я хочу сделать attr(the_thing, "$attr1$attr2$attr3"). Похоже, это возможно, но я в растерянности.

Например, я пишу некоторый код для использования ответов от Github API. Существует множество функций, таких как (они очень упрощены, например, для примера):

get_milestone <- function(org, repo) {
        response <- graphql_query(org = org, repo = repo)
        return(response$repository$milestone$issues)
}
get_pull_request <- function(org, repo) {
        response <- graphql_query(org = org, repo = repo)
        return(response$repository$pull_request$issues)
}
get_issues <- function(org, repo) {
        response <- graphql_query(org = org, repo = repo)
        return(response$repository$issues)
}

, и вы заметите единственное отличие - какие атрибуты вы извлекаете из ответа.

Я хотел бы создать простую вспомогательную функцию, такую ​​как

get_something <- function(org, repo, attr_to_get) {
        response <- graphql_query(org = org, repo = repo)
        return(attr(response, attr_to_get))
}

, а затем вызывать ее каждый раз, как

get_something(org, repo, attr_to_get="$repository$milestone$issues")
get_something(org, repo, attr_to_get="$repository$pull_request$issues")
get_something(org, repo, attr_to_get="$repository$issues")

, но этот синтаксис не работает.

Есть ли способ передать строку, чтобы указать вложенные атрибуты для извлечения из объекта? Я чувствую, что Rlang или что-то подобное может иметь отношение, но я не могу понять это.

Моей первоначальной идеей было просто сделать что-то подобное

param_list <- unlist(strsplit(attr_to_get, "\\$"))
for (p in param_list) {
    if (p != "") {
       response <- response[[p]]
    }
}

Но это чувствует себя очень уродливым и глупым для меня. Мол, должен быть однострочный способ сделать это без ручной итерации. Но, может быть, я должен просто сделать это так? Любая помощь очень ценится.

Для воспроизводимости вы можете заменить строку response <- graphql_query(org = org, repo = repo) в моей функции чем-то вроде response <- list(repository = list(milestone = list(issues=c("issue1", "issue2", "issue3")))) и затем попытаться извлечь "$repository$milestone$issues" из ответа. Спасибо!

Ответы [ 3 ]

4 голосов
/ 13 января 2020

вы можете сделать

 nm <- c("repository","milestone","issues")
 response[[nm]]

также мы можем использовать функцию purrr::pluck

  purrr::pluck(response, !!!nm)
1 голос
/ 14 января 2020

Если вы хотите использовать rlang, вот еще один возможный ответ:

# Something generic that produces a nested list with the names you specified
graphql_query <- function(org, repo){
list(repository = list(milestone = list(issues = 'hi')))
}

get_something <- function(org, repo, ...) {
response <- graphql_query(org, repo)
attr_to_get <- paste0('response$', paste(rlang::list2(...), collapse = '$'))
rlang::eval_tidy(rlang::parse_expr(attr_to_get))
}

get_something('org', 'repo', 'repository', 'milestone', 'issues')
>>> [1] "hi"

или вы можете сделать:

att_lst <- c('repository', 'milestone', 'issues')
get_something('org', 'repo', !!!att_lst)
>>> [1] "hi"
0 голосов
/ 14 января 2020

Другое базовое решение R заключается в использовании Reduce() + [[

Reduce(`[[`,list(response,"repository","milestone","issues"))

или

Reduce(`[[`,list(response,c("repository","milestone","issues")))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...