Ваш код не работает, потому что когда вы делаете names(li["first"]) = "sign"
, вы делаете:
li["first"]
- Извлечение подсписка из списка. Это создает новый список.
names(li["first"])
- Получение имен подсписка, а не исходного списка.
names(li["first"]) = "sign"
- присвоение нового имени "sign"
одному члену подсписка. Исходный список li
не имеет к этому никакого отношения, он был потерян для инструкции в тот момент, когда вы извлекли список. При выходе из функции 'names<-'
подсписок теряется, новый подсписок существует только в среде функции 'names<-'
.
И это абсолютно общее, не только для списков.
Если вы хотите изменить атрибут names
объекта R, вы должны сначала получить значение этого атрибута и указать в нем names
, а не объект. При поднаборе объекта вы создаете новый; при задании атрибута вы сохраняете объект без изменений.
Если вы не знаете порядковый номер члена списка, чье имя вы хотите изменить, правильный путь - в комментарии @Ronak Shah. И если вы хотите изменить несколько имен одновременно, используйте %in%
вместо ==
.
# Ronak Shah's comment
names(li)[names(li) == "first"] <- "sign"
names(li)
#[1] "sign" "test"
# To change 2 names use `%in%`
li2 <- list(first = "Hello", test = 3:5, second = letters[1:5])
names(li2)[names(li2) %in% c("first", "second")] <- paste("sign", 1:2, sep = "_")
names(li2)
#[1] "sign_1" "test" "sign_2"
Редактировать.
После комментария пользователя Mikko Marttila я решил объяснить это более точно.
Я думаю, что это хорошая разбивка типа "эвристики"
понимаю, что происходит, но это не совсем точно, что на самом деле
случается. Расширение функций замены в names(li["first"]) = "sign"
в конечном итоге эквивалентно делать
li <- "[<-"(li, "first", value = "names<-"(li["first"], value = "sign"))
Обычно это различие не имеет значения, но если, например, li["first"]
имеет
класс с плохим поведением 'names<-'()
метод вы против
сюрприз.
Неправильный путь.
Давайте разберем инструкцию в комментарии по частям.
Он начинается с извлечения списка из списка li
.
sub_li <- `[`(x = li, i = "first")
sub_li
#$`first`
#[1] "Hello"
Затем он устанавливает новое имя для одного из участников этого подсписка (единственный, "first"
).
sub_li <- `names<-`(x = sub_li, value = "sign")
sub_li
#$`sign`
#[1] "Hello"
Затем присваивается значение подсписка sub_li
члену li
, члену "first"
.
li <- `[<-`(li, "first", value = sub_li)
#li
#$`first`
#[1] "Hello"
#
#$test
#[1] 3 4 5
Теперь, видимо, li
не изменился. Но это так, новое значение - "Hello"
. Это не вина R, если старые и новые значения равны, R сделал то, что ему было поручено.
Чтобы доказать, что что-то произошло, я изменю значение sub_li["sign"]
и выполню точно такую же инструкцию.
sub_li["sign"] <- "Goodbye"
li <- `[<-`(li, "first", value = sub_li)
li
#$`first`
#[1] "Goodbye"
#
#$test
#[1] 3 4 5
См? R не глючил. Ошибка в том, что это не то, что задумал программист.
Правильный путь.
Правильный путь намного проще. Начните с создания исходного списка li
.
li <- list(first = c("Hello"), test = c(3, 4, 5))
Код, который работает выше (код Ронака): names(li)[names(li) == "first"] <- "sign"
. Забывая логический индекс и используя индексный номер 1
, это разбивается на две инструкции.
Первое - это присвоение '[<-'(x, i, values)
.
stuff <- `[<-`(x = names(li), i = 1, values = "sign")
Вторым является присвоение новых значений атрибуту names
.
`names<-`(x = li, value = stuff)
#$`sign`
#[1] "Hello"
#
#$test
#[1] 3 4 5
Выполняется однострочник R
li <- `names<-`(x = li, value = `[<-`(x = names(li), i = 1, values = "sign"))
li
#$`sign`
#[1] "Hello"
#
#$test
#[1] 3 4 5
Вот и все.