Как вы печатаете данные списка R, чтобы их можно было оценить как код?

#r #vega-lite #vega

Вопрос:

Как бы вы взяли дерево вложенных списков R и напечатали их таким образом, чтобы их можно было оценить как код?

Например, представьте, что у нас есть следующий код списка:

 spec <- list(
  description="An mtcards example",
  data = list(),
  mark = "point",
  encoding = list(
    x = list(field = "wt", type="quantitative"),
    y = list(field="mpg", type="quantitative"), 
    color = list(field="cyl", type="nominal")))
 

Существует ли функция f (либо в стандартной библиотеке, либо где-нибудь в CRAN), которая f(spec) выдает строку, более или менее похожую на код, используемый для определения spec , в идеале с нормальным отступом на основе длины строки? Что-то вроде:

 'list(
  description="An mtcards example",
  data = list(),
  mark = "point",
  encoding = list(
    x = list(field = "wt", type="quantitative"),
    y = list(field="mpg", type="quantitative"), 
    color = list(field="cyl", type="nominal")))'
 

Это возможно на других языках, таких как JS, Python и Clojure. Обычно структуры данных выводятся в виде литералов, которые могут быть оценены с помощью используемого языка. Существуют также специальные функции для выполнения этого с отступом (мы обычно называем это «pretty printing»). Но я не помню, чтобы когда-либо сталкивался с чем-то подобным в R (хотя прошло много лет с тех пор, как я его широко использовал), и Google оказался бесполезным в поиске чего-либо.

Для контекста прямо сейчас рассматривается возможность автоматического перевода примеров Vega-Lite / Vega на другие языки (что легко для представления данных Clojure EDN), но неясно, как мы будем это делать для спецификаций R data, используемых vegawidget. У кого-нибудь есть представление о том, как мы могли бы это сделать, или есть вдохновение написать код, чтобы сделать это вручную?

Спасибо!

Обновление: было указано, что deparse dput ) приближают нас к этому, но они по-прежнему не выводят отступы, которые вы ожидаете увидеть в реальном коде. В частности, для этого примера я получаю:

 > dput(spec)
list(description = "An mtcards example", data = list(), mark = "point",
    encoding = list(x = list(field = "wt", type = "quantitative"),
        y = list(field = "mpg", type = "quantitative"), color = list(
            field = "cyl", type = "nominal")))
 

В частности, я бы ожидал, что строки не будут прерываться в середине определения списка, если это не необходимо; color = ... должно быть в отдельной строке здесь. Я не в восторге от того, что некоторые другие записи на верхнем уровне list(...) находятся в одной строке, а другие — отдельно, но мы, вероятно, могли бы смириться с этим для примеров. Я бы никогда не ожидал увидеть color = ... список, разбитый по строкам, подобным этому, хотя в code docs, так что это не полностью решает проблему, если у кого-то нет лучшего решения.

Еще раз спасибо!

Комментарии:

1. Вы ищете dput(spec) ?

2. Это (или deparse ) может быть допустимым, но не совсем соответствует методам отступов, которые я ожидаю увидеть в реальном коде. Собираюсь проголосовать за повторное открытие, чтобы узнать, есть ли лучшее решение для этого.

3. Похоже, вы ищете комбинацию dput с code prettifier. В R нет средства улучшения собственного кода, но вы можете проверить formatR пакет. Тогда функция, которую вы ищете, будет выглядеть примерно так f <- function(x) formatR::tidy_source(text = capture.output(dput(x)), args.newline = TRUE)

4. Выполнено. Если подумать, я мог бы сам начать использовать эту функцию в Stack Overflow, чтобы сделать вопросы и ответы более разборчивыми, так что спасибо за начало этой темы!

Ответ №1:

Функция dput — это то, что мы будем использовать в качестве стандартного способа преобразования объекта R в строку текста, которая будет воспроизводить этот объект при запуске в консоли R. На самом деле, это очень часто используется при публикации вопросов и ответов в теге R в Stack Overflow. Например:

 x <- list(a = 1, b = "2")
dput(x)
#> list(a = 1, b = "2")
 

Однако dput это не всегда дает эстетически приятный результат. Похоже, то, что вы ищете, — это комбинация dput с code prettifier.

В Base R нет средства улучшения кода. Помимо всего прочего, то, что делает код красивым, довольно субъективно, и, как и в случае с большинством языков программирования, авторы R не предписывают расположение юридического кода.

Однако для R доступны пакеты, которые могут улучшать код, и их можно использовать при выводе dput . Например, мы могли бы написать такую функцию, как эта:

 f <- function(x) {
  text_con <- textConnection("output", "w")
  dput(x, text_con)
  close(text_con)
  formatR::tidy_source(text = output, args.newline = TRUE, width = 40)
}
 

Что является своего рода приукрашенным dput :

 f(spec)
#> list(
#>     description = "An mtcards example", data = list(),
#>     mark = "point", encoding = list(
#>         x = list(field = "wt", type = "quantitative"),
#>         y = list(field = "mpg", type = "quantitative"),
#>         color = list(field = "cyl", type = "nominal")
#>     )
#> )