我试图找到一种有效的(即避免使用循环)方式来应用一个函数,该函数迭代地将列表的当前和前一个(或下一个)元素作为参数,并返回结果列表(其长度)必然会缩短1个元素)。 作为一个具体的例子,
我有一个顶点列表,用于定义某个图形中的路径
vlist <- c(1,2,7,12,17)
来自使用igraph函数“lattice”构建的点阵图
G <- graph.lattice(c(5,7))
我想在vlist上应用函数“get.edge.ids”,以便返回的列表产生连接vlist中连续元素的边的id。 例如。我想要边缘1的ids - > 2,2 - &gt; 7,7 - > 12,12 - > 17
使用for循环这是微不足道的,
findEids <- function(G,vlist) {
outlist=c()
for (i in 1:(length(vlist)-1) {
outlist=append(outlist,get.edge.ids(G,c(vlist[i],vlist[i+1])))
}
return(outlist)
}
但是我想使用像apply()或reduce()这样的矢量化方法来查看是否可以让它更快地工作,因为我需要从脚本中重复调用这样的函数(例如,计算G)生成树的总伸展量。
答案 0 :(得分:3)
我使用mapply
。例如
a<-1:1000
mapply(function(x,y)x-y,a[-1000],a[-1])
它似乎比for循环版本略快:
> f <- function(x,y)x-y
> g <- function(){
o<-c();
for(i in a[-1000])o<-c(o,f(i,i+1))
> }
>
> system.time(
+ for(i in 1:1000){
+ mapply(f,a[-1000],a[-1])
+ }
+ )
user system elapsed
2.344 0.000 2.345
> system.time(for(i in 1:1000)g())
user system elapsed
3.399 0.000 3.425
答案 1 :(得分:2)
这可能对您有用:
library(zoo)
findEids <- function(gr, v.list) {
rollapply(v.list, width=2, FUN=function(x) {
get.edge.ids(gr, x)
})
}
findEids(G, vlist)
## [1] 1 4 13 22
答案 2 :(得分:2)
实际上,对于这个特定问题,您可以使用
一次查询整个路径as.vector(E(G, path=vlist))
# [1] 1 4 13 22
这是非常易读的,并且似乎比任何其他解决方案都快,尽管速度可能只对你有很长的路径很重要。
v2 <- c(1,2,7,12,17,12,7,2)
vlist <- rep(v2, 100000)
system.time(get.edge.ids(G, vlist[c(1, rep(2:(length(vlist) - 1), each = 2),
length(vlist))]))
# user system elapsed
# 0.218 0.014 0.232
system.time(as.vector(E(G, path=vlist)))
# user system elapsed
# 0.028 0.007 0.035
答案 3 :(得分:1)
虽然这不是主题中的问题的直接答案,但更具体地针对您的请求
如果你在函数vp
中查看参数get.edge.ids
的描述,你会看到
<强> VP 强>
indicent顶点,以顶点id或符号顶点的形式给出 名。 它们是成对解释的,即第一个和第二个是 用于第一个边缘,第三个和第四个用于第二个边缘,等等。
因此,在这种情况下,您只需要从vlist
创建一个新的向量,这样除了第一个和最后一个元素之外的所有元素都会重复两次。您可以使用vlist[c(1, rep(2:(length(vlist)-1), each = 2), length(vlist))]
c(1, rep(2:(length(vlist) - 1), each = 2), length(vlist))
## [1] 1 2 2 3 3 4 4 5
vlist[c(1, rep(2:(length(vlist) - 1), each = 2), length(vlist))]
## [1] 1 2 2 7 7 12 12 17
get.edge.ids(G, vlist[c(1, rep(2:(length(vlist) - 1), each = 2), length(vlist))])
## [1] 1 4 13 22
答案 4 :(得分:0)
我最近学会了使用dplyr,它可以通过mutate / transmute和paste来解决这个问题:
data.frame(x=vlist) %>%
mutate(y=lead(x)) %>%
transmute(edge=paste(x,y,sep="-->")
产生
edge
1 1-->2
2 2-->7
3 7-->12
4 12-->17
5 17-->NA