forked from hadley/plyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathliply.r
64 lines (57 loc) · 1.95 KB
/
liply.r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#' Experimental iterator based version of llply.
#'
#' Because iterators do not have known length, \code{liply} starts by
#' allocating an output list of length 50, and then doubles that length
#' whenever it runs out of space. This gives O(n ln n) performance rather
#' than the O(n ^ 2) performance from the naive strategy of growing the list
#' each time.
#'
#' @keywords manip
#' @param .iterator iterator object
#' @param .fun function to apply to each piece
#' @param ... other arguments passed on to \code{.fun}
#' @export
#' @examples
#' if(require("iterators")) {
#' system.time(dlply(baseball, "id", summarise, mean_rbi = mean(rbi)))
#' system.time({
#' baseball_id <- isplit2(baseball, baseball$id)
#' liply(baseball_id, summarise, mean_rbi = mean(rbi, na.rm = TRUE))
#' })
#' # Iterators get used up:
#' liply(baseball_id, summarise, mean_rbi = mean(rbi, na.rm = TRUE))
#' }
liply <- function(.iterator, .fun = NULL, ...) {
stopifnot(inherits(.iterator, "iter"))
if (is.null(.fun)) return(as.list(.iterator))
iterator <- itertools::ihasNext(.iterator)
if (is.character(.fun)) .fun <- each(.fun)
if (!is.function(.fun)) stop(".fun is not a function.")
result <- vector("list", 50)
i <- 0
while(itertools::hasNext(iterator)) {
piece <- iterators::nextElem(iterator)
res <- .fun(piece, ...)
# Double length of vector when necessary. Gives O(n ln n) performance
# instead of naive O(n^2)
i <- i + 1
if (i > length(result)) {
length(result) <- length(result) * 2
}
if (!is.null(res)) result[[i]] <- res
}
length(result) <- i
result
}
#' Split iterator that returns values, not indices.
#'
#' @keywords internal
#' @export
isplit2 <- function (x, f, drop = FALSE, ...) {
it <- iterators::isplit(seq_len(nrow(x)), f, drop = drop, ...)
nextEl <- function() {
i <- iterators::nextElem(it)
x[i$value, , drop = FALSE]
}
structure(list(nextElem = nextEl), class = c("abstractiter", "iter"))
}