Ответ 1
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Это относительно длинный ответ, не очень ясный и не очень интересный, поэтому не стесняйтесь пропустить его или просто прочитать (вроде) вывод.
Я пробовал немного отслеживать
[<-.data.frame
, как было предложено Ари Б. Фридманом. Отладка начинается в строке 162 функции, где есть тест, чтобы определить, является ли value
(аргумент замены) не списком.
Случай 1: value
не является списком
Тогда он рассматривается как вектор. Матрицы и массивы рассматриваются как один вектор, например, на странице справки:
Обратите внимание, что когда значением замены является массив (включая матрицу) он не рассматривается как ряд столбцов (как "data.frame и 'As.data.frame do), но вставлен как один столбец.
Если в LHS выбран только один столбец кадра данных, то единственным ограничением является то, что количество заменяемых строк должно быть равно или кратно length(value)
. Если это так, value
при необходимости перерабатывается с помощью rep
и преобразуется в список. Если length(value)==0
, нет никакой утилизации (как это невозможно), а value
просто преобразуется в список.
Если в LHS выбрано несколько столбцов кадра данных, то ограничение немного сложнее: length(value)
должно быть равно или кратно общему числу элементов, подлежащих замене, то есть количеству строк * количество столбцов.
Точный тест следующий:
(m < n * p && (m == 0L || (n * p)%%m))
Где n
- количество строк, p
количество столбцов и m
длина value
. Если условие FALSE, то value
преобразуется в матрицу n x p
(при необходимости перерабатывается), и матрица разделяется столбцами на список.
Если value
равно NULL, тогда условие TRUE равно m==0
, и функция остановлена.
Обратите внимание, что проблема возникает для каждого value
длины 0. Например,
cars1[,c("mpg")] <- numeric(0)
работает, тогда как:
cars1[,c("mpg","disp")] <- numeric(0)
не выполняется так же, как cars1[,c("mpg","disp")] <- NULL
Случай 2: value
- это список
Если value
- это список, то он используется для одновременного замены нескольких столбцов. Например:
cars1[,c("mpg","disp")] <- list(1,2)
заменит cars1$mpg
вектором 1s и cars1$disp
с вектором 2s.
Существует своего рода "двойная рециркуляция", которая происходит здесь:
- во-первых, длина списка
value
должна быть меньше или равна числу столбцов, подлежащих замене. Если это меньше, классическая утилизация выполняется. - второй, для каждого элемента списка
value
его длина должна быть равна, больше или кратна количеству строк, подлежащих замене. Если это меньше, для каждого элемента списка выполняется другая переработка, чтобы соответствовать количеству строк. Если это больше, отображается предупреждение.
Когда value
в RHS list(NULL)
, ничего действительно не происходит, поскольку рециркуляция невозможна (rep(NULL, 10)
всегда NULL
). Но код продолжается, и в конце каждого столбца, который нужно заменить, назначается NULL
, т.е. удаляется.
Резюме и (вид) заключения
data.frame
и list
ведут себя по-разному из-за специфического ограничения на кадры данных, где каждый элемент должен иметь одинаковую длину. Удаление нескольких столбцов путем назначения NULL
происходит не из-за значения NULL
, а потому, что NULL
имеет длину 0. Ошибка возникает из теста, который проверяет, является ли длина назначенного значения кратной количество элементов, подлежащих замене (количество строк * количество столбцов).
Обработка случая value=NULL
для нескольких столбцов не кажется затруднительным (добавив около четырех строк простого кода), но для этого нужно рассмотреть NULL
как частный случай. Я не могу определить, не обрабатывается ли он, потому что это нарушит логику реализации функции или потому, что у меня будут побочные эффекты, которые я не знаю.