我想获得许多(超过2个)间隔的并集:
df <- data.frame(id=c(1, 2, 3),
interval=c(
new_interval(ymd("2001-01-01"), ymd("2002-01-01")),
new_interval(ymd("2001-01-01"), ymd("2004-01-01")),
new_interval(ymd("2001-02-01"), ymd("2002-01-01"))
))
df
# id interval
# 1 1 2001-01-01 UTC--2002-01-01 UTC
# 2 2 2001-01-01 UTC--2004-01-01 UTC
# 3 3 2001-02-01 UTC--2002-01-01 UTC
lubridate::union(lubridate::union(df$interval[1], df$interval[2]),
df$interval[3])
# [1] 2001-01-01 UTC--2004-01-01 UTC
这是正确的结果。
但为什么lubridate::union
不适用于Reduce
?
Reduce(lubridate::union, df$interval )
# [1] 31536000 94608000 28857600
对象似乎也被转换为数字太子(在应用union
之前)。
答案 0 :(得分:4)
这不起作用的原因不是Reduce()
。相反,它是as.list()
,当提供的x
参数不是开头的列表时,它应用于Reduce()
内的x
。相关的行是Reduce()
中的第8行和第9行,如下所示。
head(Reduce, 9)
# ...
# 8 if (!is.vector(x) || is.object(x))
# 9 x <- as.list(x)
快速检查if()
条件可以确认这一点。
!is.vector(df$interval) || is.object(df$interval)
# [1] TRUE
因此,在as.list()
的通话中df$interval
使用了Reduce()
,这意味着df$interval
成为
as.list(df$interval)
# [[1]]
# [1] 31536000
#
# [[2]]
# [1] 94608000
#
# [[3]]
# [1] 28857600
在Reduce()
中发生任何重要操作之前(实际上这是我们目的最重要的操作)。这使得Reduce()
输出合理;它返回所有三个,因为它们是唯一的。
如果您确实需要使用Reduce()
,则可以绕过列表检查并首先使用for()
循环构建您自己的列表(因为lapply()
也不起作用)。然后我们可以将其提供给Reduce()
并获得正确的所需输出。
x <- vector("list", length(df$interval))
for(i in seq_along(x)) x[[i]] <- df$interval[i]
Reduce(lubridate::union, x)
# [1] 2001-01-01 UTC--2004-01-01 UTC
但最好为 Interval 类编写as.list()
方法并将其放在脚本的顶部。我们可以使用与上面相同的代码。
as.list.Interval <- function(x, ...) {
out <- vector("list", length(x))
for(i in seq_along(x)) out[[i]] <- x[i]
out
}
Reduce(lubridate::union, df$interval)
# [1] 2001-01-01 UTC--2004-01-01 UTC
另请注意,您可以通过抓取起始位置并使用int_end()
来执行此操作。
interval(min(slot(df$interval, "start")), max(int_end(df$interval)))
# [1] 2001-01-01 UTC--2004-01-01 UTC
答案 1 :(得分:0)
我不知道Reduce
案例,但我会这样做:
library(dplyr)
library(stringr)
df %>%
mutate(interval = str_trim(str_replace_all(interval, "(--|UTC)", " ")),
int_start = word(interval),
int_end = word(interval, -1)) %>%
summarise(interval = str_c(min(int_start),
max(int_end),
sep = "--"))
# result
interval
1 2001-01-01--2004-01-01
答案 2 :(得分:0)