Как использовать setNames для подэлементов списка

Я нашел этот вопрос, но, похоже, он мне не подходит.

Задача проста. У меня есть список, подобный следующему, полученный из фрейма данных, и я хочу setNames для подэлементов:

mydf <- data.frame(Patient=rep(paste0('Pat', 1:3), 2), Cycle=rep(paste0('C', 1:2), each=3))
mylist <- sapply(mydf, unique)

Список выглядит так:

> mylist
$Patient
[1] "Pat1" "Pat2" "Pat3"

$Cycle
[1] "C1" "C2"

Единственное, что я хочу сделать, это поставить setNames для подэлементов, чтобы они включали имя элемента, в результате чего получился окончательный список:

> mylist
$Patient
Patient-Pat1 Patient-Pat2 Patient-Pat3 
      "Pat1"       "Pat2"       "Pat3" 

$Cycle
Cycle-C1 Cycle-C2 
    "C1"     "C2" 

Теперь я мог бы пройтись по элементам один за другим, вот так:

mylist[[1]] <- setNames(mylist[[1]], paste(names(mylist)[1], mylist[[1]], sep='-'))
mylist[[2]] <- setNames(mylist[[2]], paste(names(mylist)[2], mylist[[2]], sep='-'))
...

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

Какой способ лучше всего это сделать, желательно с помощью функций apply?

Моя лучшая попытка:

sapply(mylist, setNames, paste(names(mylist), mylist, sep='-'))
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
85
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Списки с одним уровнем: перебирайте имена с помощью lapply()

Самое простое — перебирать имена списков. Мы можем передать именованный вектор в lapply(), чтобы в выходном списке были нужные имена.

lapply(
    setNames(names(mylist), names(mylist)),
    \(nm, l = mylist) setNames(l[[nm]], sprintf("%s-%s", nm, l[[nm]]))
)  
# $Patient
# Patient-Pat1 Patient-Pat2 Patient-Pat3 
#       "Pat1"       "Pat2"       "Pat3" 

# $Cycle
# Cycle-C1 Cycle-C2 
#     "C1"     "C2"

Произвольно глубокие списки

Вам нужен другой подход, если ваш список может иметь более одного вложенного уровня, например:

mylist$nested <- list(
    list("nest1", "nest2")
)

Здесь вы можете использовать rrapply::rrapply(), который имеет аргумент .xparents, который оценивается как имя родителя текущего элемента списка.

Я перенесу приведенное ниже изображение в json, потому что оно печатается лучше:

rrapply::rrapply(
    mylist,
    condition = Negate(is.list), # apply only to leafs (and not nodes)
    f = \(x, .xparents) setNames(x, sprintf("%s-%s", .xparents[1], x))
) |>
    rjson::toJSON()

Выход:

{
    "Patient": {
        "Patient-Pat1": "Pat1",
        "Patient-Pat2": "Pat2",
        "Patient-Pat3": "Pat3"
    },
    "Cycle": {
        "Cycle-C1": "C1",
        "Cycle-C2": "C2"
    },
    "nested": [
        [
            {
                "nested-nest1": "nest1"
            },
            {
                "nested-nest2": "nest2"
            }
        ]
    ]
}
Ответ принят как подходящий
sapply(names(mylist), \(x) setNames(mylist[[x]], paste(x, mylist[[x]], sep = "-")), USE.NAMES = TRUE)
#> $Patient
#> Patient-Pat1 Patient-Pat2 Patient-Pat3 
#>       "Pat1"       "Pat2"       "Pat3" 
#> 
#> $Cycle
#> Cycle-C1 Cycle-C2 
#>     "C1"     "C2"

Я собираюсь использовать это, потому что это синтаксис, который я понимаю лучше всего, и все это базово. Спасибо!

DaniCee 09.05.2024 04:26

Мы можем использовать Map.

> Map(setNames, mylist, Map(paste, names(mylist), mylist, sep='-'))
$Patient
Patient-Pat1 Patient-Pat2 Patient-Pat3 
      "Pat1"       "Pat2"       "Pat3" 

$Cycle
Cycle-C1 Cycle-C2 
    "C1"     "C2" 

Еще один с purrr и map2.
. Отличия:
-- Нет set_name
-- Нет map(map(..)) или []

new_list <- map2(
  mylist, names(mylist), 
  \(x, y) purrr::set_names(x, \(xx) paste0(y, "-", xx)))

Выход:

> new_list
$Patient
Patient-Pat1 Patient-Pat2 Patient-Pat3 
      "Pat1"       "Pat2"       "Pat3" 

$Cycle
Cycle-C1 Cycle-C2 
    "C1"     "C2" 

Буду признателен за комментарий по поводу отрицательного голоса. Это всего лишь вариант с двумя деталями, который некоторым может понравиться.

Adriano Mello 08.05.2024 18:47

Извините, я, должно быть, по ошибке проголосовал против при прокрутке на телефоне. Я отредактировал, поэтому могу отменить это.

SamR 08.05.2024 20:58

Другие вопросы по теме