#r
#r
Вопрос:
[[1]]
[[1]][[1]]
[1] 1 46 107 69 1
[[1]][[2]]
[1] 1 146 145 71 92 1
####################
[[2]]
[[2]][[1]]
[1] 1 46 18 92 1
[[2]][[2]]
[1] 1 127 145 53 168 1
Предположим, у меня есть 2 вложенных списка, как показано выше, я ищу функцию, в которой я могу обновить (скажем, 46) как в списке, так и в каком-либо другом числе в списке (скажем, 92) и обновить 92 с 46 без изменения структуры списка
Ожидаемый результат будет примерно таким
[[1]]
[[1]][[1]]
[1] 1 92 107 69 1
[[1]][[2]]
[1] 1 146 145 71 46 1
####
[[2]]
[[2]][[1]]
[1] 1 92 18 46 1
[[2]][[2]]
[1] 1 127 145 53 168 1
Библиотека Rlist имеет такие функции, как list.find/list.findi, которые работают только для именованного вложенного списка. У меня нет именованного списка
Ответ №1:
Это еще один способ добиться этого. Сначала вы просто преобразуете свой список в vector ( unlist(l)
). Выполните необходимые замены и преобразуйте его обратно в свой список ( relist(x, skeleton = l)
).
x <- unlist(l)
a <- which(x==46)
b <- which(x==92)
x[a] <- 92
x[b] <- 46
relist(x, skeleton = l)
Сравнительный анализ
library(microbenchmark)
l <- list(list(c(1, 46, 107, 69, 1), c(1, 146, 145, 71, 92, 1)), list(
c(1, 46, 18, 92, 1), c(1, 127, 145, 53, 168, 1)))
f_m0h3n <- function(l){x <- unlist(l);a <- which(x==46);b <- which(x==92);x[a] <- 92;x[b] <- 46;relist(x, l);}
f_jakub <- function(li) rapply(li, function(x) ifelse(x == 46, 92,ifelse(x==92, 46, x)), how = "list")
all.equal(f_m0h3n(l), f_jakub(l))
# [1] TRUE
microbenchmark(f_m0h3n(l), f_jakub(l))
# Unit: microseconds
# expr min lq mean median uq max neval
# f_m0h3n(l) 100.942 103.509 109.7108 107.3580 111.6355 204.879 100
# f_jakub(l) 126.178 131.738 142.8850 137.9405 143.7150 357.148 100
Больший масштаб
library(microbenchmark)
set.seed(123)
l <- list(list(sample(1000), sample(2000)),list(sample(1000), sample(2000)))
all.equal(f_m0h3n(l), f_jakub(l))
# [1] TRUE
microbenchmark(f_m0h3n(l), f_jakub(l))
# Unit: microseconds
# expr min lq mean median uq max neval
# f_m0h3n(l) 588.973 615.0645 896.9371 651.2065 692.268 2827.242 100
# f_jakub(l) 1022.683 1053.9070 1914.0769 1253.0115 2848.842 3287.898 100
Очевидно, что f_m0h3n
это работает лучше, чем f_jakub
. Разница еще более существенна для больших масштабов (время сокращается почти вдвое).
Комментарии:
1. это интересный способ отмены и повторного внесения в список. Спасибо, что поделились
Ответ №2:
Может ли это быть простым rapply
? Смотрите этот пример, где 46 заменяется 92 (и наоборот, как добавлено @akrun):
li = list(list(c(1, 46, 107, 69, 1),
c(1, 146, 145, 71, 92, 1)))
# [[1]]
# [[1]][[1]]
# [1] 1 46 107 69 1
#
# [[1]][[2]]
# [1] 1 146 145 71 92 1
rapply(li, function(x) ifelse(x == 46, 92,ifelse(x==92, 46, x)), how = "list")
# [[1]]
# [[1]][[1]]
# [1] 1 92 107 69 1
#
# [[1]][[2]]
# [1] 1 146 145 71 46 1
Это how = "list"
гарантирует, что вы получите исходную структуру обратно.
Комментарии:
1. Я предполагаю, что 92 во втором элементе списка должно быть изменено на 42. Возможно
rapply(li, function(x) ifelse(x == 46, 92,ifelse(x==92, 46, x)), how = "list")