在R中追加列表元素

4

我有两个大的、有序的整数列表。我希望在hello[i]位置处的整数length等于bye[i]位置处的整数length

这里是一个简化的可复制示例,用来模拟我的数据集:

c1<- c(0,1,0,1,1,1,0,0) |> as.integer()
c2<- c(0,1,0) |> as.integer()
c3<- c(1,1,1,0,0,0,0,0,0) |> as.integer()
c4<- c(0,1,0,1,0,0,0,1,0,1) |> as.integer()
c5<- c(0,1,0,1,0,0,0,0) |> as.integer()
c6 <-  c(1,1,1,0,0) |> as.integer()

hello<- list(c1, c2, c3)
bye<- list(c4,c5,c6)

列表输出:
hello
[[1]]
[1] 0 1 0 1 1 1 0 0

[[2]]
[1] 0 1 0

[[3]]
[1] 1 1 1 0

bye
[[1]]
 [1] 0 1 0 1 0 0 0 1 0 1

[[2]]
[1] 0 1 0 1 0 0 0 0

[[3]]
[1] 1 1 1 0 0

我希望扩展的相关列表元素的值与0相加。每个列表元素的期望输出如下所示:
hello[[2]]
[1] 0 1 0 0 0 0 0 0

bye[[2]]
[1] 0 1 0 1 0 0 0 0

到目前为止,我尝试了一个带有append语句的for循环,但是我无法让它正常工作。
我猜想lapply或purrr::map可能会提供一个更简洁的解决方案,但我仍在努力理解R中的函数式编程。非常感谢任何帮助。
5个回答

5
你可以试试:
Map(\(x, y) c(x, integer(y))[1L:y], hello, pmax(lengths(hello), lengths(bye)))

或者稍微变化一下:
Map(\(x, y, z) c(x, integer(max(0L, z-y))), hello, lengths(hello), lengths(bye))

[[1]]
 [1] 0 1 0 1 1 1 0 0 0 0

[[2]]
[1] 0 1 0 0 0 0 0 0

[[3]]
[1] 1 1 1 0 0 0 0 0 0

2
其他的Map变体
Map(
    \(x, y) c(x, rep(0,y)), 
    hello, 
    pmax(lengths(bye) - lengths(hello), 0)
)

或者

Map(
    \(x, y) replace(d <- `length<-`(x, y), is.na(d), 0), 
    hello, 
    pmax(lengths(bye), lengths(hello))
)

提供

[[1]]
 [1] 0 1 0 1 1 1 0 0 0 0

[[2]]
[1] 0 1 0 0 0 0 0 0

[[3]]
[1] 1 1 1 0 0 0 0 0 0

1
使用 length(x) <- value
# template list:
str(bye)
#> List of 3
#>  $ : int [1:10] 0 1 0 1 0 0 0 1 0 1
#>  $ : int [1:8] 0 1 0 1 0 0 0 0
#>  $ : int [1:5] 1 1 1 0 0

# if padding with NA values is OK, this would be enough:
hello_2 <- mapply(`length<-`, hello, lengths(bye))
str(hello_2)
#> List of 3
#>  $ : int [1:10] 0 1 0 1 1 1 0 0 NA NA
#>  $ : int [1:8] 0 1 0 NA NA NA NA NA
#>  $ : int [1:5] 1 1 1 0 0

# to replace NAs with 0:
hello_3 <- hello_2 |> lapply(\(v) `[<-`(v, is.na(v), 0))
str(hello_3)
#> List of 3
#>  $ : num [1:10] 0 1 0 1 1 1 0 0 0 0
#>  $ : num [1:8] 0 1 0 0 0 0 0 0
#>  $ : num [1:5] 1 1 1 0 0

2023-08-21创建,使用reprex v2.0.2


1
这真的很棒!我从来不知道你可以像这样使用\length<-`。小问题 - 我更喜欢在这里(几乎总是)使用Map()而不是mapply() - 在这种情况下输出没有区别,但当我的输入发生变化时,mapply()`会决定将我的结果简化为矩阵,这让我感到困惑。 - SamR

1
另一种方法是使用imap
imap(hello, \(h, i) if (length(h) > length(bye[[i]])) h[1:length(bye[[i]])] else c(bye[[i]], rep(0, length(bye[[i]]) - length(h))))

对我来说不清楚你希望在 hello 已经比 bye 更长的情况下发生什么。 我将其缩短为 hello 的前 n 个字符,其中 n 是 bye 的长度。


0
对于单向填充(根据相关“再见”项目的长度调整“你好”项目的长度),您可以使用以下方法:
library(purrr)

hello2 <- map2(hello, bye, function(h,b) {
  if(length(b)>length(h)) {
    h <- append(h, rep(0, length(b)-length(h)))
  } else {
    h
  }
})

map2在两个列表上进行逐对迭代,并对每对调用给定的函数。在这里,我们检测是否需要进行长度调整,然后附加所需数量的零。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接