#r #plot #variadic-functions #getter-setter
#r #сюжет #переменные-функции #получатель-сеттер
Вопрос:
Я работаю над некоторыми общими функциями доступа для par()
опции в R.
getPar
getPar = function(key)
{
par()[[key]];
}
Это работает, как и ожидалось.
getPar("mar");
setPar
# save memory ... restoreState ... pdf
setPar = function(key, val)
{
# par(mar=c(0.25, 0.25, 0.25, 0.25)
# R.O. indicates read-only arguments: These may only be used in queries and cannot be set. ("cin", "cra", "csi", "cxy", "din" and "page" are always read-only.)
# https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/par
pnames = names( par(no.readonly = TRUE) );
if(is.element(key, pnames))
{
par()[[key]] = val;
}
}
Это не работает:
mar = c(0.25, 0.25, 0.25, 0.25);
setPar("mar", mar);
И выдает ошибку:
Error in par()[[key]] = val : invalid (NULL) left side of assignment
Есть идеи о том, как я могу написать setter
функцию, как описано в общих чертах?
Да, я понимаю, я могу перейти par(mar = c(0.25, 0.25, 0.25, 0.25))
непосредственно к «установке» значения. Я специально ищу решение, которое будет работать внутри этой простой setter
функции. Вариационный подход.
Ответ №1:
Для присвоения спискам (т. Е. [<-
И [[<-
) Требуется объект в LHS присваивания, а не выражение, которое создает список. Аналогично,
A <- list(a=1)
A$b <- 2
A
# $a
# [1] 1
# $b
# [1] 2
list(a=1)$b <- 3
# Error in list(a = 1)$b <- 3 :
# target of assignment expands to non-language object
Я предлагаю вам изменить setPar
, чтобы фактически установить значение, используя par
, а не пытаться работать со списком.
setPar = function(key, val)
{
# par(mar=c(0.25, 0.25, 0.25, 0.25)
# R.O. indicates read-only arguments: These may only be used in queries and cannot be set. ("cin", "cra", "csi", "cxy", "din" and "page" are always read-only.)
# https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/par
pnames = names( par(no.readonly = TRUE) );
if(is.element(key, pnames))
{
par(setNames(list(val), key))
}
}
par("mar")
# [1] 5.1 4.1 4.1 2.1
setPar("mar", 1:4)
par("mar")
# [1] 1 2 3 4
Комментарии:
1. Итак, он появляется
getPar
иpar
возвращает то же самое, и я также могу удалить эту идею «доступа к списку».2. Да, ваш
getPar
эквивалентpar
. Однако, если вы действительно хотите попасть в сорняки,par(key)
это почти в 4 раза быстрее, чемpar()[[key]]
, и в остальном совершенно эквивалентно. Даже более медленныйpar()[[key]]
процесс занимает порядка 34 микросекунд на моей машине, так что это не критическая точка сбоя кода. Попробуйтеbench::mark(par("mar"), par()[["mar"]])
увидеть более полное сравнение.3. Когда мы говорим о
efficiency
временных критериях, это только один фактор. Важным фактором также является меньшая когнитивная нагрузка.4. Я полностью согласен. То, что вы называете «когнитивной нагрузкой», я обычно объединяю в ремонтопригодность (для меня) и удобочитаемость (для других и для будущего меня), которые являются (imo) разумными причинами для намеренного предотвращения истинного улучшения производительности с использованием запутанных или неясных сокращений кода-golf в коде. (К сожалению, иногда моя читаемость имеет измеримый уровень разочарования, когда нагрузка умножается на 3 строки …). Но да, вы правы, и именно поэтому я предположил, что тратить несколько микросекунд не стоило, если вы предпочитаете прежний код.
5. Я полностью согласен. Возможно, присвоение функции чего-то более подробного, например
getParKey
, уменьшит мою будущую «когнитивную нагрузку». R потрясающий, но и причудливый, как показывает ваш ответ. Иногда он следует правилам абстрактной алгебры обратных функций, и оболочкуget/set
легче написать:getAttribute = function(key, obj) { attributes(obj)[[key]]; } setAttribute = function(key, value, obj) { attributes(obj)[[key]] = value; obj; # no object referencing, so I must return }