R: замена 2 значений во вложенном списке

#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")