在给定索引处将元素插入到向量中

Insert elements into a vector at given indexes

提问人:Aaron Statham 提问时间:9/30/2009 最后编辑:HenrikAaron Statham 更新时间:5/9/2023 访问量:93206

问:

我有一个逻辑向量,我希望在特定索引处插入新元素。我在下面想出了一个笨拙的解决方案,但有没有更简洁的方法?

probes <- rep(TRUE, 15)
ind <- c(5, 10)
probes.2 <- logical(length(probes)+length(ind))
probes.ind <- ind + 1:length(ind)
probes.original <- (1:length(probes.2))[-probes.ind]
probes.2[probes.ind] <- FALSE
probes.2[probes.original] <- probes

print(probes)

[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

print(probes.2)

[1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
[13]  TRUE  TRUE  TRUE  TRUE  TRUE

所以它有效,但看起来很丑 - 有什么建议吗?

r

评论

0赞 hadley 9/30/2009
为什么需要插入?
0赞 Aaron Statham 9/30/2009
长话短说,但基本上在寻找 TRUE 的运行,但有我想打破运行的预定位置。我第一次使用“rle”,但它的扩展性很差,所以想出了这个肮脏的矢量解决方案

答:

2赞 Harlan 9/30/2009 #1

这有点棘手。这是一种方法。它遍历列表,每次都插入,因此效率不高。

probes <- rep(TRUE, 15)
probes.ind <- ind + 0:(length(ind)-1)
for (i in probes.ind) {
  probes <- c(probes[1:i], FALSE, probes[(i+1):length(probes)])
}

> probes
 [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
[13]  TRUE  TRUE  TRUE  TRUE  TRUE

如果 ind 有重复的元素,这甚至应该有效,尽管 ind 确实需要排序才能使探测器 .ind 构造正常工作。

8赞 Jonathan Chang 9/30/2009 #2

这个怎么样:

> probes <- rep(TRUE, 15)
> ind <- c(5, 10)

> probes.ind <- rep(NA, length(probes))
> probes.ind[ind] <- FALSE
> new.probes <- as.vector(rbind(probes, probes.ind))
> new.probes <- new.probes[!is.na(new.probes)]
> new.probes
 [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
[13]  TRUE  TRUE  TRUE  TRUE  TRUE

评论

5赞 Harlan 9/30/2009
偷偷摸摸!使用 as.vector 对 rbind 创建的矩阵进行逐列折叠的事实。这是因为矩阵只是一个向量,其中包含指示行数的附加信息,并且内部按列顺序存储。这是 R 语言定义的一部分,但可能有点晦涩难懂,具体取决于谁在阅读代码......
0赞 Rob 10/11/2012
@Harlan 很好的解释。在处理此示例时,这会产生很大的不同。
45赞 Marek 9/30/2009 #3

你可以用索引做一些魔术:

首先使用输出值创建向量:

probs <- rep(TRUE, 15)
ind <- c(5, 10)
val <- c( probs, rep(FALSE,length(ind)) )
# > val
#  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
# [13]  TRUE  TRUE  TRUE FALSE FALSE

现在把戏。每个旧元素都获得排名,每个新元素获得半排名

id  <- c( seq_along(probs), ind+0.5 )
# > id
#  [1]  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0 11.0 12.0 13.0 14.0 15.0
# [16]  5.5 10.5

然后使用按正确的顺序排序:order

val[order(id)]
#  [1]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
# [13]  TRUE  TRUE  TRUE  TRUE  TRUE

评论

1赞 Aaron Statham 9/30/2009
漂亮而鬼鬼祟祟 - 订单与数千/数百万个元素的扩展程度如何?
0赞 Marek 9/30/2009
在 1.58GHz Core2 上,system.time(order(rnorm(1e6))) 需要 <2s
0赞 Phil van Kleur 7/20/2020
这真是太优雅了,马雷克!
0赞 bgbrink 11/9/2022
请注意,如果要插入连续的元素,则此操作不起作用。在此示例中,如果 ind 为 c(5,6),则生成的向量将显示 [...]FALSE TRUE FALSE [...] 而不是 [...]假 假 真 [...]。
0赞 Marek 11/13/2022
@bgbrink 它的工作方式与问题中的解决方案相同。
90赞 Shane 9/30/2009 #4

这些都是非常有创意的方法。我认为使用索引绝对是要走的路(Marek 的解决方案非常好)。

我只想提一下,有一个函数可以大致做到这一点:.append()

probes <- rep(TRUE, 15)
probes <- append(probes, FALSE, after=5)
probes <- append(probes, FALSE, after=11)

或者你可以用你的索引递归方式来做到这一点(你需要在每次迭代中增加“after”值):

probes <- rep(TRUE, 15)
ind <- c(5, 10)
for(i in 0:(length(ind)-1)) 
    probes <- append(probes, FALSE, after=(ind[i+1]+i))

顺便说一句,这个问题以前在R-Help上也被问过。正如 Barry 所说:

“实际上,我想说的是没有办法做到这一点,因为我认为你实际上不能插入到一个向量中 - 你必须创建一个产生插入错觉的新向量!”

评论

0赞 Aaron Statham 9/30/2009
我不知道追加功能,感谢您引起我的注意!我应该在我的问题中指定我不想要循环,因为我的真实向量将有数千/数百万个元素
1赞 coip 8/12/2016
并且可以设置在向量的开头插入一个新值。after = 0
0赞 Yaakov Baruch 1/5/2017
如果像你所假设的那样进行排序,你能更简单地反向循环吗?indfor(i in length(ind):1) append(..., after=ind[i])
12赞 Wojciech Sobala 3/1/2011 #5
probes <- rep(TRUE, 1000000)
ind <- c(50:100)
val <- rep(FALSE,length(ind))

new.probes <- vector(mode="logical",length(probes)+length(val))
new.probes[-ind] <- probes
new.probes[ind] <- val

一些时间安排: 我的方法 用户系统已过 0.03 0.00 0.03

马立克方法 用户系统已过 0.18 0.00 0.18

R 追加 for 循环 用户系统已过 1.61 0.48 2.10

评论

2赞 aoles 9/13/2016
好主意,似乎是最有效的方法!但是,您需要移动所有索引才能使其按预期工作,即在对 .ind <- ind + 0:(length(ind)-1)new.probes
1赞 Davor Josipovic 6/21/2017
您可以省略最后一步(和定义),只需使用要替换的值进行初始化:。这使得它更快。valnew.probesnew.probes <- rep(FALSE,length(probes)+length(val))
1赞 Marek 7/22/2020
-1 如果它是正确的,那将是一个很好的答案。您需要(,而不是像第一条评论那样从 0 开始)。和 or 不如一个神秘。ind <- ind + seq_len(length(ind))1:length(ind)logical(length(probes)+length(val))rep(FALSE, length(probes)+length(val))vector(mode=...
1赞 unknown 8/9/2017 #6

或者,您可以使用 miscTools 包中的 insertRow 函数来完成。

probes <- rep(TRUE, 15)
ind <- c(5,10)
for (i in ind){
    probes <- as.vector(insertRow(as.matrix(probes), i, FALSE))
}

评论

0赞 Chris 2/14/2018
我来这里是为了寻找那个。使用名称进行排序的技巧很酷,加深了我对语言的理解,但这更适合我的情况。
0赞 Ben 9/16/2020 #7

我想出了一个很好的答案,它很容易理解,而且运行起来相当快,建立在上面 Wojciech 的答案之上。我将在这里的示例中调整该方法,但它可以很容易地泛化为几乎任何数据类型,以实现任意缺失点模式(如下所示)。

probes <- rep(TRUE, 15)
ind <- c(5,10)

probes.final <- rep(FALSE, length(probes)+length(ind))
probes.final[-ind] <- probes

我需要的数据是定期采样的,但许多样本被丢弃,生成的数据文件仅包含保留的数据戳和测量值。我需要生成一个包含所有时间戳的向量,以及一个为抛出的时间戳插入 NA 的数据向量。我使用了从这里偷来的“不在”功能,让它更简单一些。

`%notin%` <- Negate(`%in%`)
dat <- rnorm(50000) # Data given
times <- seq(from=554.3, by=0.1, length.out=70000] # "Original" time stamps
times <- times[-sample(2:69999, 20000)] # "Given" times with arbitrary points missing from interior

times.final <- seq(from=times[1], to=times[length(times)], by=0.1)
na.ind <- which(times.final %notin% times)
dat.final <- rep(NA, length(times.final))
dat.final[-na.ind] <- dat
0赞 Paulo 11/20/2020 #8

嗯,嗨,我也有同样的疑问,但我听不懂人们的回答,因为我还在学习语言。所以我试着自己做,我想它有效!我创建了一个向量,我想在第 3、5 和 6 个索引后插入值 100。这就是我写的。

vector <-  c(0:9)
indexes <-  c(6, 3, 5)
indexes <- indexes[order(indexes)]
i <-  1
j <-  0

while(i <= length(indexes)){
  vector <- append(vector, 100, after = indexes[i] + j)
  i <-i + 1
  j <- j + 1
}
vector

向量“索引”必须按升序排列才能正常工作。这就是为什么我把它们放在第三行的原因。 变量“j”是必需的,因为在每次迭代时,新向量的长度都会增加,原始值也会移动。 如果您希望将新值并排插入,只需重复索引的编号即可。例如,通过分配索引 <- c(3, 5, 5, 5, 6),您应该得到向量 == 0 1 2 100 3 4 100 100 100 5 100 6 7 8 9

1赞 Marius 5/9/2023 #9

使用 Wojciech Sobala 的解决方案,我制作了一个适用于任何数据模式的通用函数:

insertValuesAtIdx <- function(vec,values,idx)
{
  res<-vector(mode=mode(vec),length = length(vec)+length(idx))
  res[-idx]<-vec
  res[idx]<-values
  return(res)
}
insertValuesAtIdx(LETTERS,"a",c(4,6))
insertValuesAtIdx(1:100,c(1000,1001,1002),c(4,6,56))