Title: | Fast, Compact Iterators and Tools |
---|---|
Description: | A fresh take on iterators in R. Designed to be cross-compatible with the 'iterators' package, but using the 'nextOr' method will offer better performance as well as more compact code. With batteries included: includes a collection of iterator constructors and combinators ported and refined from the 'iterators', 'itertools', and 'itertools2' packages. |
Authors: | Peter Meilstrup [cre, aut, cph], Folashade Daniel [aut], Revolution Analytics [aut, cph], Steve Weston [aut, cph], John A. Ramey [aut, cph], Kayla Schaefer [aut], Hadley Wickham [aut] |
Maintainer: | Peter Meilstrup <[email protected]> |
License: | GPL (>= 3) |
Version: | 1.0 |
Built: | 2024-11-09 03:21:44 UTC |
Source: | https://github.com/crowding/iterors |
Collect all (or some given number of) values from an iteror, returning a vector of the given type.
## S3 method for class 'iteror' as.list(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.double(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.numeric(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.logical(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.character(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.vector(x, mode)
## S3 method for class 'iteror' as.list(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.double(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.numeric(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.logical(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.character(x, n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' as.vector(x, mode)
x |
an iterable object |
n |
the maximum number of elements to return. |
... |
Unused arguments will throw an error. |
mode |
What mode to use for the output vector. |
The returned value will be n
elements long if the
iterator did not stop.
concat take
concat
collects all values from an iterable object, and pastes
them end to end into one vector. In other words concat
is to
as.list.iteror
as c
is to list
.
concat(obj, mode = "list", n = Inf, ...) ## Default S3 method: concat(obj, mode = "list", n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' concat(obj, mode = "list", n = Inf, length.out = Inf, ...)
concat(obj, mode = "list", n = Inf, ...) ## Default S3 method: concat(obj, mode = "list", n = as.integer(2^31 - 1), ...) ## S3 method for class 'iteror' concat(obj, mode = "list", n = Inf, length.out = Inf, ...)
obj |
An iteror. |
mode |
The mode of vector to return. |
n |
The maximum number of times to call |
... |
passed along to iteror constructor. |
length.out |
The target size of the output vector (after
results have been pasted together). If the iteror ends (or emits
|
a vector with mode mode
.
it <- i_apply(icount(), seq_len) # [1], [1, 2], [1, 2, 3], ... concat(it, n=4, mode="numeric") # [1, 1, 2, 1, 2, 3, 1, 2, 3, 4] concat(it, length.out=4, mode="numeric") # [1, 1, 2, 1, 2, 3, 1, 2, 3, 4]
it <- i_apply(icount(), seq_len) # [1], [1, 2], [1, 2, 3], ... concat(it, n=4, mode="numeric") # [1, 1, 2, 1, 2, 3, 1, 2, 3, 4] concat(it, length.out=4, mode="numeric") # [1, 1, 2, 1, 2, 3, 1, 2, 3, 4]
Advances the iterator n-steps ahead without returning anything.
consume(obj, n = Inf, ...) ## S3 method for class 'iteror' consume(obj, n = Inf, ...)
consume(obj, n = Inf, ...) ## S3 method for class 'iteror' consume(obj, n = Inf, ...)
obj |
an iterable object |
n |
The number of elements to consume. |
... |
passed along to iteror constructor. |
obj
, invisibly.
take collect
it <- iteror(1:10) # Skips the first 5 elements consume(it, n=5) # Returns 6 nextOr(it, NA) it2 <- iteror(letters) # Skips the first 4 elements consume(it2, 4) # Returns 'e' nextOr(it2, NA)
it <- iteror(1:10) # Skips the first 5 elements consume(it, n=5) # Returns 6 nextOr(it, NA) it2 <- iteror(letters) # Skips the first 4 elements consume(it2, 4) # Returns 'e' nextOr(it2, NA)
Counts the number of elements in an iterator. NOTE: The iterator is consumed in the process.
count(object, ...)
count(object, ...)
object |
an iterable object |
... |
passed along to iteror constructor. |
the number of elements in the iterator
take consume as.list.iteror
count(1:5) == length(1:5) it <- iteror(1:5) count(it) == length(1:5) it2 <- i_chain(1:3, 4:5, 6) count(it2) it3 <- i_chain(1:3, levels(iris$Species)) count(it3)
count(1:5) == length(1:5) it <- iteror(1:5) count(it) == length(1:5) it2 <- i_chain(1:3, 4:5, 6) count(it2) it3 <- i_chain(1:3, levels(iris$Species)) count(it3)
Returns the dot product of two numeric iterables of equal length
dotproduct(vec1, vec2)
dotproduct(vec1, vec2)
vec1 |
the first |
vec2 |
the second iterable object |
the dot product of the iterators
it <- iteror(1:3) it2 <- iteror(4:6) dotproduct(it, it2) # 32 it <- iteror(1:4) it2 <- iteror(7:10) dotproduct(1:4, 7:10) # 90
it <- iteror(1:3) it2 <- iteror(4:6) dotproduct(it, it2) # 32 it <- iteror(1:4) it2 <- iteror(7:10) dotproduct(1:4, 7:10) # 90
wrapped <- ihasnext(obj)
wraps an iteror object with the
ihasNext
class. Then hasNext(wrapped)
will indicate if the
iterator has another element.
hasNext(obj, ...) ihasNext(obj, ...)
hasNext(obj, ...) ihasNext(obj, ...)
obj |
an iterable |
... |
extra arguments may be passed along to iteror. |
A class ihasNext
was introduced in the itertools
package to try to reduce the boilerplate around extracting the
next value using iterators::nextElem. ihasNext
is included
in iterors
for backward compatibility with iterator code; however,
it is less needed when using the nextOr iteration method, as you can
directly give an action to take at end of iteration.
Logical value indicating whether the iterator has a next element.
# The bad old style of consuming an iterator in a loop with `nextElem`: it <- ihasNext(iteror(c('a', 'b', 'c'))) tryCatch(repeat { print(iterators::nextElem(it)) }, error=function(err) { if (conditionMessage(err) != "StopIteration") stop(err) }) # with ihasNext, this became: it <- ihasNext(iteror(c('a', 'b', 'c'))) while (hasNext(it)) print(iterators::nextElem(it)) # But using `nextOr` all you need is: iteror(c('a', 'b', 'c')) repeat print(nextOr(it, break))
# The bad old style of consuming an iterator in a loop with `nextElem`: it <- ihasNext(iteror(c('a', 'b', 'c'))) tryCatch(repeat { print(iterators::nextElem(it)) }, error=function(err) { if (conditionMessage(err) != "StopIteration") stop(err) }) # with ihasNext, this became: it <- ihasNext(iteror(c('a', 'b', 'c'))) while (hasNext(it)) print(iterators::nextElem(it)) # But using `nextOr` all you need is: iteror(c('a', 'b', 'c')) repeat print(nextOr(it, break))
i_apply(obj, f)
returns the iteror that applies f
to
each element of the given iterable obj
. It is an iterator
equivalent of lapply
.
i_apply(obj, f, ...)
i_apply(obj, f, ...)
obj |
an iterable. |
f |
a function |
... |
Additional arguments will be passed along to |
An iteror.
To apply a function of multiple arguments to multiple
iterators, see i_map. To split an array over margins (like
iterators::i_apply
use iteror(obj, by=MARGIN
Create an iterator that iterates over another iterator until a specified
function returns FALSE
. This can be useful for breaking out of a
foreach loop, for example.
i_break(iterable, finished, ...)
i_break(iterable, finished, ...)
iterable |
Iterable to iterate over. |
finished |
Function that returns a logical value. The iterator stops
when this function returns |
... |
Further arguments forwarded to |
Originally from the itertools
package.
an iteror which will stop when finished()
is TRUE
# See how high we can count in a tenth of a second mkfinished <- function(time) { starttime <- proc.time()[3] function() proc.time()[3] > starttime + time } length(as.list(i_break(icount(), mkfinished(0.1))))
# See how high we can count in a tenth of a second mkfinished <- function(time) { starttime <- proc.time()[3] function() proc.time()[3] > starttime + time } length(as.list(i_break(icount(), mkfinished(0.1))))
Create an iterator that issues lists of values from the underlying iterable. This is useful for manually “chunking” values from an iterable.
i_chunk(iterable, size, mode = "list", fill, ...)
i_chunk(iterable, size, mode = "list", fill, ...)
iterable |
Iterable to iterate over. |
size |
Maximum number of values from |
mode |
Mode of the objects returned by the iterator. |
fill |
Value to use to pad the last chunk to size, if it is short. If missing, no padding will be done. |
... |
Further arguments will be forwarded to |
an iteror that yields items of length size
and mode mode
.
iteror.default
Argument size
does not need to be an integer, for instance a
chunk
of 3.5 will produce chunks of sizes 3 and 4
alternating. The precise behavior will be subject to floating
point precision.
# Split the vector 1:10 into "chunks" with a maximum length of three it <- i_chunk(1:10, 3) repeat print(unlist(nextOr(it, break))) # Same as previous, but return integer vectors rather than lists it <- i_chunk(1:10, 3, mode='integer') repeat print(unlist(nextOr(it, break))) it <- i_chunk(iterators::iter(1:5), 2, fill=NA) # List: list(1, 2, 3) nextOr(it, NULL) # List: list(4, 5, NA) nextOr(it, NULL) it2 <- i_chunk(levels(iris$Species), 4, fill="weeee") # Returns: list("setosa", "versicolor", "virginica", "weeee") nextOr(it2, NA)
# Split the vector 1:10 into "chunks" with a maximum length of three it <- i_chunk(1:10, 3) repeat print(unlist(nextOr(it, break))) # Same as previous, but return integer vectors rather than lists it <- i_chunk(1:10, 3, mode='integer') repeat print(unlist(nextOr(it, break))) it <- i_chunk(iterators::iter(1:5), 2, fill=NA) # List: list(1, 2, 3) nextOr(it, NULL) # List: list(4, 5, NA) nextOr(it, NULL) it2 <- i_chunk(levels(iris$Species), 4, fill="weeee") # Returns: list("setosa", "versicolor", "virginica", "weeee") nextOr(it2, NA)
i_concat(obj)
takes an iterable that returns
iterables, and chains together all inner values of iterables into
one iterator. Analogous to unlist(recursive=FALSE)
.
i_chain
for iterators is analogous to c()
on vectors. i_chain
constructs an iteror that returns elements from the first
argument until it is exhausted, then elements from the next
argument, and so on until all arguments have been exhausted.
i_concat(obj, ...) i_chain(...)
i_concat(obj, ...) i_chain(...)
obj |
an iterable. |
... |
multiple iterable arguments |
iteror that iterates through each argument in sequence
Peter Meilstrup
it <- i_chain(1:3, 4:5, 6) as.list(it) it2 <- i_chain(1:3, levels(iris$Species)) as.list(it2)
it <- i_chain(1:3, 4:5, 6) as.list(it) it2 <- i_chain(1:3, levels(iris$Species)) as.list(it2)
Constructs an iterator that drops elements from the iterable object
as
long as the predicate
function is true; afterwards, every element of
iterable
object is returned.
i_dropwhile(object, predicate, ...)
i_dropwhile(object, predicate, ...)
object |
an iterable object |
predicate |
a function that determines whether an element is |
... |
Further arguments forwarded to iteror. |
Because the iterator does not return any elements until the predicate
first becomes false, there may have a lengthy start-up time before elements
are returned.
An iteror object.
# Filters out numbers exceeding 3 not_too_large <- function(x) { x <= 3 } it <- i_dropwhile(1:8, not_too_large) as.list(it) # Same approach but uses an anonymous function it2 <- i_dropwhile(seq(2, 20, by=2), function(x) x <= 10) as.list(it2)
# Filters out numbers exceeding 3 not_too_large <- function(x) { x <= 3 } it <- i_dropwhile(1:8, not_too_large) as.list(it) # Same approach but uses an anonymous function it2 <- i_dropwhile(seq(2, 20, by=2), function(x) x <= 10) as.list(it2)
Constructs an iterator that returns the elements of an object along with each
element's indices. Enumeration is useful when looping through an
object
and a counter is required.
The i_enumerate
method for arrays allows splitting an
array by arbitrary margins, including by multiple margins. The
index
element returned will be a vector (or if chunking is used, a
matrix) of indices.
i_enumerate(obj, ...) ienumerate(obj, ...) ## Default S3 method: i_enumerate(obj, ..., recycle = FALSE, chunkSize, chunks) i_enum(obj, ...) ## S3 method for class 'array' i_enumerate( obj, ..., recycle = FALSE, chunkSize, chunks, by = c("cell", "row", "column"), rowMajor = TRUE, drop = FALSE )
i_enumerate(obj, ...) ienumerate(obj, ...) ## Default S3 method: i_enumerate(obj, ..., recycle = FALSE, chunkSize, chunks) i_enum(obj, ...) ## S3 method for class 'array' i_enumerate( obj, ..., recycle = FALSE, chunkSize, chunks, by = c("cell", "row", "column"), rowMajor = TRUE, drop = FALSE )
obj |
object to return indefinitely. |
... |
Undocumented. |
recycle |
Whether to restart the iterator after finishing the array. |
chunkSize |
How large a chunk to take along the specified dimension. |
chunks |
How many chunks to divide the array into. |
by |
Which array margins to iterate over. Can be "row", "col", "cell", or a vector of numerical indices. |
rowMajor |
If TRUE, the first index varies fastest, if FALSE, the last index varies fastest. |
drop |
Whether to drop marginalized dimensions. If chunking is used, this has no effect. |
This function is intended to follow the convention used in Python's
enumerate
function where the primary difference is that a list is
returned instead of Python's tuple
construct.
Each call to nextElem
returns a list with two
elements:
a counter
the current value of object
i_enum
is an alias to i_enumerate
to save a few keystrokes.
First appeared in package iterators2
.
These are two closely closely related functions:
i_enumerate
accepts an iterable, and will only emit a single
index starting with 1. ienumerate
is a generic with methods for
vectors and arrays, supporting all chunking and recycling
options, and returning multiple indices for arrays.
iterator that returns the values of obj
along with the
index of the object.
Peter Meilstrup
set.seed(42) it <- i_enumerate(rnorm(5)) as.list(it) # Iterates through the columns of the iris data.frame it2 <- i_enum(iris) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) a <- array(1:27, c(3, 3, 3)) as.list(i_enumerate(a, by=c(1, 2), drop=TRUE)) as.list(i_enumerate(a, by=c(3), drop=FALSE)) as.list(i_enumerate(a, by=c(2, 3), chunkSize=7))
set.seed(42) it <- i_enumerate(rnorm(5)) as.list(it) # Iterates through the columns of the iris data.frame it2 <- i_enum(iris) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) nextOr(it2, NA) a <- array(1:27, c(3, 3, 3)) as.list(i_enumerate(a, by=c(1, 2), drop=TRUE)) as.list(i_enumerate(a, by=c(3), drop=FALSE)) as.list(i_enumerate(a, by=c(2, 3), chunkSize=7))
i_keep(iterable, predicate)
constructs an iterator that filters
elements from iterable returning only those for which the predicate
is TRUE
.
i_keep(iterable, predicate, ...) i_drop(iterable, predicate, ...)
i_keep(iterable, predicate, ...) i_drop(iterable, predicate, ...)
iterable |
an iterable object. |
predicate |
a function that determines whether an element is
|
... |
passed along to iteror constructor. |
Originally called 'ifilter' from package
itertools
. Renamed because the order of arguments has changed
to put the iterable in the first argument, the better to be used
with the |>
operator.
iterator object
i_drop i_keepwhile i_dropwhile
# Filters out odd numbers and retains only even numbers is_even <- function(x) { x %% 2 == 0 } it <- i_keep(1:10, is_even) as.list(it) # Similar idea here but anonymous function is used to retain only odd # numbers it2 <- i_drop(1:10, function(x) x %% 2 == 0) nextOr(it2, NA) # 1 nextOr(it2, NA) # 3 nextOr(it2, NA) # 5 nextOr(it2, NA) # 7 nextOr(it2, NA) # 9 is_vowel <- function(x) { x %in% c('a', 'e', 'i', 'o', 'u') } it3 <- i_keep(letters, is_vowel) as.list(it3) # Filters out even numbers and retains only odd numbers is_even <- function(x) { x %% 2 == 0 } it <- i_drop(1:10, is_even) as.list(it) # Similar idea here but anonymous function is used to filter out odd # numbers it2 <- i_drop(1:10, function(x) x %% 2 == 1) as.list(it2) is_vowel <- function(x) { x %in% c('a', 'e', 'i', 'o', 'u') } it3 <- i_drop(letters, is_vowel) nextOr(it3, NA) # b nextOr(it3, NA) # c nextOr(it3, NA) # d nextOr(it3, NA) # f nextOr(it3, NA) # g # nextOr(it, NA) continues through the rest of the consonants
# Filters out odd numbers and retains only even numbers is_even <- function(x) { x %% 2 == 0 } it <- i_keep(1:10, is_even) as.list(it) # Similar idea here but anonymous function is used to retain only odd # numbers it2 <- i_drop(1:10, function(x) x %% 2 == 0) nextOr(it2, NA) # 1 nextOr(it2, NA) # 3 nextOr(it2, NA) # 5 nextOr(it2, NA) # 7 nextOr(it2, NA) # 9 is_vowel <- function(x) { x %in% c('a', 'e', 'i', 'o', 'u') } it3 <- i_keep(letters, is_vowel) as.list(it3) # Filters out even numbers and retains only odd numbers is_even <- function(x) { x %% 2 == 0 } it <- i_drop(1:10, is_even) as.list(it) # Similar idea here but anonymous function is used to filter out odd # numbers it2 <- i_drop(1:10, function(x) x %% 2 == 1) as.list(it2) is_vowel <- function(x) { x %in% c('a', 'e', 'i', 'o', 'u') } it3 <- i_drop(letters, is_vowel) nextOr(it3, NA) # b nextOr(it3, NA) # c nextOr(it3, NA) # d nextOr(it3, NA) # f nextOr(it3, NA) # g # nextOr(it, NA) continues through the rest of the consonants
Constructs an iterator that returns elements from an iterable object
as long as the given predicate
function returns TRUE
.
i_keepwhile(object, predicate, ...)
i_keepwhile(object, predicate, ...)
object |
an iterable object |
predicate |
a function that determines whether an element is |
... |
passed along to |
iterator object
# Filters out numbers exceeding 5 not_too_large <- function(x) { x <= 5 } it <- i_keepwhile(1:100, not_too_large) unlist(as.list(it)) == 1:5 # Same approach but uses an anonymous function it2 <- i_keepwhile(seq(2, 100, by=2), function(x) x <= 10) unlist(as.list(it2)) == c(2, 4, 6, 8, 10)
# Filters out numbers exceeding 5 not_too_large <- function(x) { x <= 5 } it <- i_keepwhile(1:100, not_too_large) unlist(as.list(it)) == 1:5 # Same approach but uses an anonymous function it2 <- i_keepwhile(seq(2, 100, by=2), function(x) x <= 10) unlist(as.list(it2)) == c(2, 4, 6, 8, 10)
Create an iterator that limits the specified iterable to a specified number of items.
i_limit(iterable, n, ...)
i_limit(iterable, n, ...)
iterable |
Iterable to iterate over. |
n |
Maximum number of values to return. |
... |
Extra arguments for |
Originally from the itertools
package.
an iteror which will stop after yielding n
values.
# Limit icount to only return three values as.list(i_limit(icount(), 3))
# Limit icount to only return three values as.list(i_limit(icount(), 3))
Constructs an iterator that computes the given function f
using the
arguments from each of the iterables given in ...
.
i_map(f, ...)
i_map(f, ...)
f |
a function |
... |
multiple arguments to iterate through in sequence |
The iterator returned is exhausted when the shortest iterable in ...
is exhausted. Note that i_map
does not recycle arguments as
Map
does.
The primary difference between i_starmap
and
i_map
is that the former expects an iterable object
whose elements are already grouped together, while the latter case groups the
arguments together before applying the given function. The choice is a matter
of style and convenience.
iterator that returns the values of object
along with the
index of the object.
pow <- function(x, y) { x^y } it <- i_map(pow, c(2, 3, 10), c(5, 2, 3)) as.list(it) # Similar to the above, but because the second vector is exhausted after two # calls to `nextElem`, the iterator is exhausted. it2 <- i_map(pow, c(2, 3, 10), c(5, 2)) as.list(it2) # Another similar example but with lists instead of vectors it3 <- i_map(pow, list(2, 3, 10), list(5, 2, 3)) nextOr(it3, NA) # 32 nextOr(it3, NA) # 9 nextOr(it3, NA) # 1000
pow <- function(x, y) { x^y } it <- i_map(pow, c(2, 3, 10), c(5, 2, 3)) as.list(it) # Similar to the above, but because the second vector is exhausted after two # calls to `nextElem`, the iterator is exhausted. it2 <- i_map(pow, c(2, 3, 10), c(5, 2)) as.list(it2) # Another similar example but with lists instead of vectors it3 <- i_map(pow, list(2, 3, 10), list(5, 2, 3)) nextOr(it3, NA) # 32 nextOr(it3, NA) # 9 nextOr(it3, NA) # 1000
Constructs an iterator that filters elements from iterable returning only
those for which the corresponding element from selectors
is
TRUE
.
i_mask(object, selectors)
i_mask(object, selectors)
object |
an iterable object |
selectors |
an iterable that determines whether the corresponding
element in |
The iterator stops when either object
or selectors
has been
exhausted.
iterator object
# Filters out odd numbers and retains only even numbers n <- 10 selectors <- rep(c(FALSE, TRUE), n) it <- i_mask(seq_len(n), selectors) as.list(it) # Similar idea here but anonymous function is used to filter out even # numbers n <- 10 it2 <- i_mask(seq_len(10), rep(c(TRUE, FALSE), n)) as.list(it2) it3 <- i_mask(letters, letters %in% c('a', 'e', 'i', 'o', 'u')) as.list(it3)
# Filters out odd numbers and retains only even numbers n <- 10 selectors <- rep(c(FALSE, TRUE), n) it <- i_mask(seq_len(n), selectors) as.list(it) # Similar idea here but anonymous function is used to filter out even # numbers n <- 10 it2 <- i_mask(seq_len(10), rep(c(TRUE, FALSE), n)) as.list(it2) it3 <- i_mask(letters, letters %in% c('a', 'e', 'i', 'o', 'u')) as.list(it3)
Constructs an iterator that returns an iterable object
before padding
the iterator with the given fill
value indefinitely.
i_pad(object, fill = NA, ...)
i_pad(object, fill = NA, ...)
object |
an iterable object |
fill |
the value to pad the indefinite iterator after the initial
|
... |
Passed along to iteror constructor. |
iterator that returns object
followed indefinitely by the
fill
value
it <- iteror(1:9) it_i_pad <- i_pad(it) as.list(i_slice(it_i_pad, end=9)) # Same as as.list(1:9) it2 <- iteror(1:9) it2_i_pad <- i_pad(it2) as.list(i_slice(it2_i_pad, end=10)) # Same as as.list(c(1:9, NA)) it3 <- iteror(1:9) it3_i_pad <- i_pad(it3, fill=TRUE) as.list(i_slice(it3_i_pad, end=10)) # Same as as.list(c(1:9, TRUE))
it <- iteror(1:9) it_i_pad <- i_pad(it) as.list(i_slice(it_i_pad, end=9)) # Same as as.list(1:9) it2 <- iteror(1:9) it2_i_pad <- i_pad(it2) as.list(i_slice(it2_i_pad, end=10)) # Same as as.list(c(1:9, NA)) it3 <- iteror(1:9) it3_i_pad <- i_pad(it3, fill=TRUE) as.list(i_slice(it3_i_pad, end=10)) # Same as as.list(c(1:9, TRUE))
Create an iterator that recycles a specified iterable. On the first repeat the iterable is buffered into memory until it finishes, then we repeat the same sequence of values.
i_recycle(iterable, times = Inf, ...)
i_recycle(iterable, times = Inf, ...)
iterable |
The iterable to recycle. |
times |
integer. Number of times to recycle the values .
Default value of |
... |
Further arguments will be passed along to iteror. |
Originally from the itertools
package.
an iteror recycling the values from the underlying iterable.
# Recycle over 'a', 'b', and 'c' three times i <- i_recycle(letters[1:3], 3) as.character(i) it <- i_recycle(1:3) nextOr(it, NA) # 1 nextOr(it, NA) # 2 nextOr(it, NA) # 3 nextOr(it, NA) # 1 nextOr(it, NA) # 2 nextOr(it, NA) # 3 nextOr(it, NA) # 1 it2 <- i_recycle(1:3, times=2) as.list(it2)
# Recycle over 'a', 'b', and 'c' three times i <- i_recycle(letters[1:3], 3) as.character(i) it <- i_recycle(1:3) nextOr(it, NA) # 1 nextOr(it, NA) # 2 nextOr(it, NA) # 3 nextOr(it, NA) # 1 nextOr(it, NA) # 2 nextOr(it, NA) # 3 nextOr(it, NA) # 1 it2 <- i_recycle(1:3, times=2) as.list(it2)
An analogue of the rep
function operating on iterables.
i_rep(iterable, times = 1, length.out = NULL, each = 1, ...)
i_rep(iterable, times = 1, length.out = NULL, each = 1, ...)
iterable |
The iterable to iterate over repeatedly. |
times |
How many times to recycle the underlying iteror (via i_recycle). |
length.out |
The maximum length of output. If this is given
|
each |
The number of times to repeat each element. You can pass a vector (recycled), or another iterable, to repeat each element a varying number of times. |
... |
further arguments passed along to |
Note that arguments times
and each
can work slightly
differently from rep; times
must always be of length 1; to
repeat each element a specific number of times, provide a vector to
each
rather than times
.
Originally from the itertools
package.
an iteror yilding and repeating values from iterable
.
as.numeric(i_rep(1:4, 2)) as.numeric(i_rep(1:4, each=2)) as.numeric(i_rep(1:4, each=c(2,2,2,2))) as.numeric(i_rep(1:4, each=c(2,1,2,1))) as.numeric(i_rep(1:4, each=2, len=4)) as.numeric(i_rep(1:4, each=2, len=10)) as.numeric(i_rep(1:4, each=2, times=3)) # Note `rep` makes `times` behave like `each` when given a vector. # `i_rep` does not reproduce this behavior; give the vector to `each`. # These are equivalent: as.numeric(i_rep(1:4, each = 1:8, times=2)) rep(rep(1:4, times=2), times=1:8)
as.numeric(i_rep(1:4, 2)) as.numeric(i_rep(1:4, each=2)) as.numeric(i_rep(1:4, each=c(2,2,2,2))) as.numeric(i_rep(1:4, each=c(2,1,2,1))) as.numeric(i_rep(1:4, each=2, len=4)) as.numeric(i_rep(1:4, each=2, len=10)) as.numeric(i_rep(1:4, each=2, times=3)) # Note `rep` makes `times` behave like `each` when given a vector. # `i_rep` does not reproduce this behavior; give the vector to `each`. # These are equivalent: as.numeric(i_rep(1:4, each = 1:8, times=2)) rep(rep(1:4, times=2), times=1:8)
Create an iterator that returns a value a specified number of times.
i_repeat(x, times)
i_repeat(x, times)
x |
The value to return repeatedly. |
times |
The number of times to repeat the value. Default value is infinity. |
Originally from the itertools
package.
an iteror.
# Repeat a value 10 times unlist(as.list(i_repeat(42, 10)))
# Repeat a value 10 times unlist(as.list(i_repeat(42, 10)))
This is an iterator equivalent of rle; it produces one output
value for each run if identical values in its input, along with the
lenght of the run. i_rle_inverse()
performs the inverse
transformstion.
i_rle(obj, cmp = identical, ...) i_rleinv(obj, ...)
i_rle(obj, cmp = identical, ...) i_rleinv(obj, ...)
obj |
An iterable |
cmp |
A function to use for comparison. It should take two
arguments and return |
... |
further arguments forwarded to |
An iterator returning entries of the form list(length=n, value=X)
.
i_rleinv
recreates the original data from the output of i_rle
.
Peter Meilstrup
i_dedupe
it <- isample(c(TRUE, FALSE), 1, replace=TRUE) rle <- i_rle(it) x <- take(rle, 10) as.logical(i_rleinv(x))
it <- isample(c(TRUE, FALSE), 1, replace=TRUE) rle <- i_rle(it) x <- take(rle, 10) as.logical(i_rleinv(x))
Constructs an iterator that traverses each given iterable in a roundrobin order. That is, the iterables are traversed in an alternating fashion such that the each element is drawn from the next iterable. If an iterable has no more available elements, it is skipped, and the next element is taken from the next iterable having available elements.
i_roundrobin(...)
i_roundrobin(...)
... |
multiple arguments to iterate through in roundrobin sequence |
iterator that alternates through each argument in roundrobin sequence
it <- iteror(c("A", "B", "C")) it2 <- iteror("D") it3 <- iteror(c("E", "F")) as.list(i_roundrobin(it, it2, it3)) # A D E B F C it_rr <- i_roundrobin(1:3, 4:5, 7:10) as.list(it_rr) # 1 4 7 2 5 8 3 9 10
it <- iteror(c("A", "B", "C")) it2 <- iteror("D") it3 <- iteror(c("E", "F")) as.list(i_roundrobin(it, it2, it3)) # A D E B F C it_rr <- i_roundrobin(1:3, 4:5, 7:10) as.list(it_rr) # 1 4 7 2 5 8 3 9 10
Constructs an iteror that returns elements from an iterable following the
given sequence with starting value start
and ending value end
.
The sequence's step size is given by step
.
i_slice(object, start = 1, end = NULL, step = 1, ...)
i_slice(object, start = 1, end = NULL, step = 1, ...)
object |
iterable object through which this function iterates |
start |
the index of the first element to return from |
end |
the index of the last element to return from |
step |
the step size of the sequence |
... |
passed along to |
The iterable given in object
is traversed beginning with element
having index specified in start
. If start
is greater than 1,
then elements from the object
are skipped until start
is
reached. By default, elements are returned consecutively. However, if the
step
size is greater than 1, elements in object
are skipped.
If stop
is Inf
(default), the iteration continues until the
iteror is exhausted unless end
is specified. In this case,
end
specifies the sequence position to stop iteration.
Originally from package itertools2
.
iteror that returns object
in sequence
it <- i_slice(1:5, start=2) nextOr(it, NULL) # 2 nextOr(it, NULL) # 3 nextOr(it, NULL) # 4 nextOr(it, NULL) # 5 it2 <- i_slice(1:10, start=2, end=5) unlist(as.list(it2)) == 2:5 it3 <- i_slice(1:10, start=2, end=9, step=2) unlist(as.list(it3)) == c(2, 4, 6, 8)
it <- i_slice(1:5, start=2) nextOr(it, NULL) # 2 nextOr(it, NULL) # 3 nextOr(it, NULL) # 4 nextOr(it, NULL) # 5 it2 <- i_slice(1:10, start=2, end=5) unlist(as.list(it2)) == 2:5 it3 <- i_slice(1:10, start=2, end=9, step=2) unlist(as.list(it3)) == c(2, 4, 6, 8)
Constructs an iteror that applies the function f
concurrently to the
elements within the list x
.
i_starmap(f, x) i_star(f, x)
i_starmap(f, x) i_star(f, x)
f |
a function to apply to the elements of |
x |
an iterable object |
The iteror returned is exhausted when the shortest element in x
is exhausted. Note that i_starmap
does not recycle arguments as
Map
does.
The primary difference between i_starmap
and
i_map
is that the former expects an iterable object
whose elements are already grouped together, while the latter case groups the
arguments together before applying the given function. The choice is a matter
of style and convenience.
iterator that returns the values of object
along with the
index of the object.
pow <- function(x, y) { x^y } it <- i_starmap(pow, list(c(2, 3, 10), c(5, 2, 3))) unlist(as.list(it)) == c(32, 9, 1000) # Similar to the above, but because the second vector is exhausted after two # calls to `nextElem`, the iterator is exhausted. it2 <- i_starmap(pow, list(c(2, 3, 10), c(5, 2))) unlist(as.list(it2)) == c(32, 9) # Another similar example but with lists instead of vectors it3 <- i_starmap(pow, list(list(2, 3, 10), list(5, 2, 3))) as.list(it3) # Computes sum of each row in the iris data set # Numerically equivalent to base::rowSums() tolerance <- sqrt(.Machine$double.eps) iris_x <- iris[, -5] it4 <- i_starmap(sum, iris_x) unlist(as.list(it4)) - rowSums(iris_x) < tolerance
pow <- function(x, y) { x^y } it <- i_starmap(pow, list(c(2, 3, 10), c(5, 2, 3))) unlist(as.list(it)) == c(32, 9, 1000) # Similar to the above, but because the second vector is exhausted after two # calls to `nextElem`, the iterator is exhausted. it2 <- i_starmap(pow, list(c(2, 3, 10), c(5, 2))) unlist(as.list(it2)) == c(32, 9) # Another similar example but with lists instead of vectors it3 <- i_starmap(pow, list(list(2, 3, 10), list(5, 2, 3))) as.list(it3) # Computes sum of each row in the iris data set # Numerically equivalent to base::rowSums() tolerance <- sqrt(.Machine$double.eps) iris_x <- iris[, -5] it4 <- i_starmap(sum, iris_x) unlist(as.list(it4)) - rowSums(iris_x) < tolerance
i_tee(obj, n)
consumes and buffers the output of a single iterator
obj
so that it can be read by n
independent sub-iterators.
i_tee(obj, n, max = 2^16 - 1, ...)
i_tee(obj, n, max = 2^16 - 1, ...)
obj |
an iterable object |
n |
the number of iterators to return |
max |
The maximum number of values to buffer. |
... |
passed along to |
It works by saving the output of source obj
in a queue, while
each sub-iterator has a "read pointer" indexing into the
queue. Items are dropped from the queue after all sub-iterators
have seen them.
This means that if one sub-iterator falls far behind the others, or
equivalently if one sub-iterator reads far ahead its cohort the
others, the intervening values will be kept in memory. The max
argument gives a limit on how many items will be held. If this
limit is exceeded due to one sub-iterator reading far ahead of the
others, an error will be thrown when that sub-iterator attempts to
read a new value.
a list of n
iterators.
Peter Meilstrup
Create an iterator that iterates over another iterator for a specified period of time, and then stops. This can be useful when you want to search for something, or run a test for awhile, and then stop.
i_timeout(iterable, time, ...)
i_timeout(iterable, time, ...)
iterable |
Iterable to iterate over. |
time |
The time interval to iterate for, in seconds. |
... |
passed along to |
Originally from the itertools
package.
an iteror yielding values from iterable
so long as time
is in the future
# See how high we can count in a tenth of a second length(as.list(i_timeout(icount(), 0.1)))
# See how high we can count in a tenth of a second length(as.list(i_timeout(icount(), 0.1)))
Constructs an iterator that extracts each unique element in turn from an
iterable object
. Order of the elements is maintained. This function is
an iterator analogue to unique.
i_unique(object, digest = rlang::hash, ...)
i_unique(object, digest = rlang::hash, ...)
object |
an iterable object |
digest |
Optionally specify a custom hash function
(e.g. |
... |
Extra arguments are forwarded to iteror. |
NOTE: In order to determine whether an element is unique, a list of previous unique elements is stored. In doing so, the list can potentially become large if there are a large number of unique elements.
an iterator that returns only the unique elements from
object
i_dedupe
it <- i_chain(rep(1, 4), rep(2, 5), 4:7, 2) as.list(i_unique(it)) # 1 2 4 5 6 7 it2 <- iterators::iter(c('a', 'a', "A", "V")) as.list(i_unique(it2)) # a A V x <- as.character(gl(5, 10)) it_unique <- i_unique(x) as.list(it_unique) # 1 2 3 4 5
it <- i_chain(rep(1, 4), rep(2, 5), 4:7, 2) as.list(i_unique(it)) # 1 2 4 5 6 7 it2 <- iterators::iter(c('a', 'a', "A", "V")) as.list(i_unique(it2)) # a A V x <- as.character(gl(5, 10)) it_unique <- i_unique(x) as.list(it_unique) # 1 2 3 4 5
Each element returned by i_window(obj)
consists of n
consecutive
elements from the underlying obj
, with the window advancing
forward by one element each iteration.
i_window(obj, n, tail, ...)
i_window(obj, n, tail, ...)
obj |
An iterable. |
n |
The width of the window to apply |
tail |
If a value is given, tails will be included at the beginning and end of iteration, filled with the given value. |
... |
passed along to |
an iteror.
Peter Meilstrup
#' @examples it <- i_window(iteror(letters[1:4]), 2) nextOr(it, NA) # list("a", "b") nextOr(it, NA) # list("b", "c") nextOr(it, NA) # list("c", "d") it2 <- i_window(icount(5), 2) nextOr(it2, NA) # list(1, 2) nextOr(it2, NA) # list(2, 3) nextOr(it2, NA) # list(3, 4) nextOr(it2, NA) # list(4, 5) it <- i_window(letters[1:4], 2) nextOr(it, NA) # list("a", "b") nextOr(it, NA) # list("b", "c") nextOr(it, NA) # list("c", "d") it <- i_window(letters[1:4], 3) nextOr(it) # list("a", "b", "c") nextOr(it) # list("b", "c", "d") it <- i_window(letters[1:4], 3, tail=" ") nextOr(it) # list(" ", " ", "a") nextOr(it) # list(" ", "a", "b") nextOr(it) # list("a", "b", "c") nextOr(it) # list("b", "c", "d") nextOr(it) # list("c", "d", " ") nextOr(it) # list("d", " ", " ")
#' @examples it <- i_window(iteror(letters[1:4]), 2) nextOr(it, NA) # list("a", "b") nextOr(it, NA) # list("b", "c") nextOr(it, NA) # list("c", "d") it2 <- i_window(icount(5), 2) nextOr(it2, NA) # list(1, 2) nextOr(it2, NA) # list(2, 3) nextOr(it2, NA) # list(3, 4) nextOr(it2, NA) # list(4, 5) it <- i_window(letters[1:4], 2) nextOr(it, NA) # list("a", "b") nextOr(it, NA) # list("b", "c") nextOr(it, NA) # list("c", "d") it <- i_window(letters[1:4], 3) nextOr(it) # list("a", "b", "c") nextOr(it) # list("b", "c", "d") it <- i_window(letters[1:4], 3, tail=" ") nextOr(it) # list(" ", " ", "a") nextOr(it) # list(" ", "a", "b") nextOr(it) # list("a", "b", "c") nextOr(it) # list("b", "c", "d") nextOr(it) # list("c", "d", " ") nextOr(it) # list("d", " ", " ")
The resulting iterator aggregates one element from each of the iterables into a list for each iteration. Used for lock-step iteration over several iterables at a time.
i_zip(...) i_zip_longest(..., fill = NA)
i_zip(...) i_zip_longest(..., fill = NA)
... |
multiple arguments to iterate through in parallel |
fill |
the value used to replace missing values when the iterables in
|
For [i_zip]
, the output will finish when any of the underlying iterables finish.
Originally from the itertools
package.
Originally from package itertools2
.
iterator that iterates through each argument in sequence
# Iterate over two iterables of different sizes as.list(i_zip(a=1:2, b=letters[1:3])) it <- i_zip_longest(x=1:3, y=4:6, z=7:9) nextOr(it, NA) # list(x=1, y=4, z=7) nextOr(it, NA) # list(x=2, y=5, z=8) nextOr(it, NA) # list(x=3, y=6, z=9) it2 <- i_zip_longest(1:3, 4:8) nextOr(it2, NA) # list(1, 4) nextOr(it2, NA) # list(2, 5) nextOr(it2, NA) # list(3, 6) nextOr(it2, NA) # list(NA, 7) nextOr(it2, NA) # list(NA, 8) it3 <- i_zip_longest(1:2, 4:7, levels(iris$Species), fill="w00t") nextOr(it3, NA) # list(1, 4, "setosa") nextOr(it3, NA) # list(2, 5, "versicolor") nextOr(it3, NA) # list("w00t", 6, "virginica") nextOr(it3, NA) # list("w00t", 7, "w00t")
# Iterate over two iterables of different sizes as.list(i_zip(a=1:2, b=letters[1:3])) it <- i_zip_longest(x=1:3, y=4:6, z=7:9) nextOr(it, NA) # list(x=1, y=4, z=7) nextOr(it, NA) # list(x=2, y=5, z=8) nextOr(it, NA) # list(x=3, y=6, z=9) it2 <- i_zip_longest(1:3, 4:8) nextOr(it2, NA) # list(1, 4) nextOr(it2, NA) # list(2, 5) nextOr(it2, NA) # list(3, 6) nextOr(it2, NA) # list(NA, 7) nextOr(it2, NA) # list(NA, 8) it3 <- i_zip_longest(1:2, 4:7, levels(iris$Species), fill="w00t") nextOr(it3, NA) # list(1, 4, "setosa") nextOr(it3, NA) # list(2, 5, "versicolor") nextOr(it3, NA) # list("w00t", 6, "virginica") nextOr(it3, NA) # list("w00t", 7, "w00t")
Constructs an iterator generates all combinations of a vector taken m
at a time. This function is similar to combn
.
icombinations(object, m, replacement = FALSE)
icombinations(object, m, replacement = FALSE)
object |
vector |
m |
the length of each combination |
replacement |
Generate combinations with replacement? Default: no. |
By default, the combinations are without replacement so that elements are
not repeated. To generate combinations with replacement, set
replacement=TRUE
.
The function implementation is loosely based on the combinations
function from Python's itertools. Combinations with replacement are based on
combinations_with_replacement
from the same Python library.
iterator that generates all combinations of object
# Combinations without replacement it <- icombinations(1:4, m=2) nextOr(it, NA) # c(1, 2) nextOr(it, NA) # c(1, 3) nextOr(it, NA) # c(1, 4) nextOr(it, NA) # c(2, 3) nextOr(it, NA) # c(2, 4) nextOr(it, NA) # c(3, 4) # Combinations without replacement it <- icombinations(1:4, m=2, replacement=TRUE) nextOr(it, NA) # c(1, 1) nextOr(it, NA) # c(1, 2) nextOr(it, NA) # c(1, 3) nextOr(it, NA) # c(1, 4) nextOr(it, NA) # c(2, 2) nextOr(it, NA) # c(2, 3) nextOr(it, NA) # c(2, 4) nextOr(it, NA) # c(3, 3) nextOr(it, NA) # c(3, 4) nextOr(it, NA) # c(4, 4) it3 <- icombinations(1:5, m=2) as.list(it3) utils::combn(x=1:5, m=2, simplify=FALSE)
# Combinations without replacement it <- icombinations(1:4, m=2) nextOr(it, NA) # c(1, 2) nextOr(it, NA) # c(1, 3) nextOr(it, NA) # c(1, 4) nextOr(it, NA) # c(2, 3) nextOr(it, NA) # c(2, 4) nextOr(it, NA) # c(3, 4) # Combinations without replacement it <- icombinations(1:4, m=2, replacement=TRUE) nextOr(it, NA) # c(1, 1) nextOr(it, NA) # c(1, 2) nextOr(it, NA) # c(1, 3) nextOr(it, NA) # c(1, 4) nextOr(it, NA) # c(2, 2) nextOr(it, NA) # c(2, 3) nextOr(it, NA) # c(2, 4) nextOr(it, NA) # c(3, 3) nextOr(it, NA) # c(3, 4) nextOr(it, NA) # c(4, 4) it3 <- icombinations(1:5, m=2) as.list(it3) utils::combn(x=1:5, m=2, simplify=FALSE)
Returns an iterator that counts starting from one.
icountn(vn)
takes a vector specifying an array size,
and returns an iterator over array indices. Each returned element
is a vector the same length as vn, with the first index varying fastest.
If vn has a names attribute the output will have the same names.
icount(count = Inf, ..., recycle = FALSE, chunkSize, chunks) icountn(vn, ..., recycle = FALSE, chunkSize, chunks, rowMajor = TRUE)
icount(count = Inf, ..., recycle = FALSE, chunkSize, chunks) icountn(vn, ..., recycle = FALSE, chunkSize, chunks, rowMajor = TRUE)
count |
number of times that the iterator will fire. Use NA or Inf to make an iterator that counts forever. |
... |
Undocumented |
recycle |
Whether to restart the count after finishing. |
chunkSize |
How many valies to return from each call to nextOr(). |
chunks |
How many chunks to split the input. Either |
vn |
A vector of integers. |
rowMajor |
If |
Originally from the iterators
package.
The counting iterator.
For more control over starting number and step size, see iseq.
# create an iterator that counts from 1 to 3. it <- icount(3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # expect NULL x <- icount(5) repeat print(nextOr(x, break)) it2 <- icount(100) all.equal(as.numeric(it2), 1:100) as.list(icountn(c(2, 3)))
# create an iterator that counts from 1 to 3. it <- icount(3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # expect NULL x <- icount(5) repeat print(nextOr(x, break)) it2 <- icount(100) all.equal(as.numeric(it2), 1:100) as.list(icountn(c(2, 3)))
Constructs an iterator that removes runs of repeated elements from the underlying iterator. Order of the elements is maintained. Only the element just seen is remembered for determining whether to drop.
idedup(object, cmp = identical, ...)
idedup(object, cmp = identical, ...)
object |
an iterable object |
cmp |
A function to use for comparison. |
... |
passed along to |
Originated as itertools2::iunique_lastseen
.
object
.
an iterator that skips over duplicate items from teh unterlying iterator.
i_rle
it <- i_chain(rep(1,4), rep(2, 5), 4:7, 2) it_i_unique <- idedup(it) as.list(it_i_unique) # 1 2 4 5 6 7 2 it2 <- iteror(c('a', 'a', "A", 'a', 'a', "V")) i_dedupe <- idedup(it2) as.list(idedup) # a A a V
it <- i_chain(rep(1,4), rep(2, 5), 4:7, 2) it_i_unique <- idedup(it) as.list(it_i_unique) # 1 2 4 5 6 7 2 it2 <- iteror(c('a', 'a', "A", 'a', 'a', "V")) i_dedupe <- idedup(it2) as.list(idedup) # a A a V
Returns an iterator dividing a value into integer chunks, such that
sum(idiv(n, ...)) == floor(n)
idiv(count, ..., recycle = FALSE, chunkSize, chunks)
idiv(count, ..., recycle = FALSE, chunkSize, chunks)
count |
The total |
... |
Unused. |
recycle |
Whether to restart the count after finishing. |
chunkSize |
the maximum size of the pieces that |
chunks |
the number of pieces that |
Originally from the iterators
package.
The dividing iterator.
# divide the value 10 into 3 pieces it <- idiv(10, chunks = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # expect NULL # divide the value 10 into pieces no larger than 3 it <- idiv(10, chunkSize = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # end of iterator
# divide the value 10 into 3 pieces it <- idiv(10, chunks = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # expect NULL # divide the value 10 into pieces no larger than 3 it <- idiv(10, chunkSize = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # end of iterator
Given a number of vectors as arguments, constructs an iterator that enumerates the Cartesian product of all arguments.
igrid( ..., recycle = FALSE, chunkSize, chunks, simplify = FALSE, rowMajor = TRUE )
igrid( ..., recycle = FALSE, chunkSize, chunks, simplify = FALSE, rowMajor = TRUE )
... |
Named vectors to iterate over. |
recycle |
If TRUE, the iteror starts over on reaching the end. |
chunkSize |
Optional; how many rows to return in each step. |
chunks |
Optional; how many chunks to divide the input into. |
simplify |
If TRUE, inputs are coerced to a common data type and results are returned in a vector (or matrix if chunking is enabled). If FALSE, results are returned as a list (or data.frame if chunking). |
rowMajor |
If TRUE, the left-most indices change fastest. If FALSE the rightmost indices change fastest. |
Although they share the same end goal, igrid
can yield
drastic memory savings compared to expand.grid
.
an iteror that iterates through each element from the Cartesian product of its arguments.
# Simulate a doubly-nested loop with a single while loop it <- igrid(a=1:3, b=1:2) repeat { x <- nextOr(it, break) cat(sprintf('a = %d, b = %d\n', x$a, x$b)) } it <- igrid(x=1:3, y=4:5) nextOr(it, NA) # list(x=1, y=4) nextOr(it, NA) # list(x=1, y=5) nextOr(it, NA) # list(x=2, y=4) nextOr(it, NA) # list(x=2, y=5) nextOr(it, NA) # list(x=3, y=4) nextOr(it, NA) # list(x=3, y=5) # Second Cartesian product nextOr(it, NA) # list(x=1, y=4) nextOr(it, NA) # list(x=1, y=5) nextOr(it, NA) # list(x=2, y=4) nextOr(it, NA) # list(x=2, y=5) nextOr(it, NA) # list(x=3, y=4) nextOr(it, NA) # list(x=3, y=5) # igrid is an iterator equivalent to base::expand.grid() # Large data.frames are not created unless the iterator is manually consumed a <- 1:2 b <- 3:4 c <- 5:6 it3 <- igrid(a=a, b=b, c=c) df_igrid <- do.call(rbind, as.list(it3)) df_igrid <- data.frame(df_igrid) # Compare df_igrid with the results from base::expand.grid() base::expand.grid(a=a, b=b, c=c)
# Simulate a doubly-nested loop with a single while loop it <- igrid(a=1:3, b=1:2) repeat { x <- nextOr(it, break) cat(sprintf('a = %d, b = %d\n', x$a, x$b)) } it <- igrid(x=1:3, y=4:5) nextOr(it, NA) # list(x=1, y=4) nextOr(it, NA) # list(x=1, y=5) nextOr(it, NA) # list(x=2, y=4) nextOr(it, NA) # list(x=2, y=5) nextOr(it, NA) # list(x=3, y=4) nextOr(it, NA) # list(x=3, y=5) # Second Cartesian product nextOr(it, NA) # list(x=1, y=4) nextOr(it, NA) # list(x=1, y=5) nextOr(it, NA) # list(x=2, y=4) nextOr(it, NA) # list(x=2, y=5) nextOr(it, NA) # list(x=3, y=4) nextOr(it, NA) # list(x=3, y=5) # igrid is an iterator equivalent to base::expand.grid() # Large data.frames are not created unless the iterator is manually consumed a <- 1:2 b <- 3:4 c <- 5:6 it3 <- igrid(a=a, b=b, c=c) df_igrid <- do.call(rbind, as.list(it3)) df_igrid <- data.frame(df_igrid) # Compare df_igrid with the results from base::expand.grid() base::expand.grid(a=a, b=b, c=c)
Constructs an iterator generates all permutations of an iterable object. By
default, full-length permutations are generated. If m
is specified,
successive m
length permutations are instead generated.
ipermutations(object, m = NULL)
ipermutations(object, m = NULL)
object |
vector |
m |
length of permutations. By default, full-length permutations are generated. |
The implementation is loosely based on that of Python's itertools.
iterator that generates all permutations of object
it <- ipermutations(1:3) nextOr(it, NA) # c(1, 2, 3) nextOr(it, NA) # c(1, 3, 2) nextOr(it, NA) # c(3, 1, 2) nextOr(it, NA) # c(3, 2, 1) nextOr(it, NA) # c(2, 3, 1) nextOr(it, NA) # c(2, 1, 3) it2 <- ipermutations(letters[1:4]) # 24 = 4! permutations of the letters a, b, c, and d as.list(it2)
it <- ipermutations(1:3) nextOr(it, NA) # c(1, 2, 3) nextOr(it, NA) # c(1, 3, 2) nextOr(it, NA) # c(3, 1, 2) nextOr(it, NA) # c(3, 2, 1) nextOr(it, NA) # c(2, 3, 1) nextOr(it, NA) # c(2, 1, 3) it2 <- ipermutations(letters[1:4]) # 24 = 4! permutations of the letters a, b, c, and d as.list(it2)
Returns an iterator over the rows of a data frame stored in a file in table
format. It is a wrapper around the standard read.table
function.
iread.table(file, ..., verbose = FALSE)
iread.table(file, ..., verbose = FALSE)
file |
the name of the file to read the data from. |
... |
all additional arguments are passed on to the |
verbose |
logical value indicating whether or not to print the calls to
|
Originally from the iterators
package.
The file reading iterator.
In this version of iread.table
, both the read.table
arguments header
and row.names
must be specified. This is
because the default values of these arguments depend on the contents of the
beginning of the file. In order to make the subsequent calls to
read.table
work consistently, the user must specify those arguments
explicitly. A future version of iread.table
may remove this
requirement.
Create an iterator to read binary data from a connection.
ireadBin( con, what = "raw", n = 1L, size = NA_integer_, signed = TRUE, endian = .Platform$endian, ipos = NULL )
ireadBin( con, what = "raw", n = 1L, size = NA_integer_, signed = TRUE, endian = .Platform$endian, ipos = NULL )
con |
A connection object or a character string naming a file or a raw vector. |
what |
Either an object whose mode will give the mode of the vector to
be read, or a character vector of length one describing the mode: one of
“numeric”, “double”, “integer”, “int”,
“logical”, “complex”, “character”, “raw”.
Unlike |
n |
integer. The (maximal) number of records to be read each time the iterator is called. |
size |
integer. The number of bytes per element in the byte stream. The default, ‘NA_integer_’, uses the natural size. |
signed |
logical. Only used for integers of sizes 1 and 2, when it determines if the quantity on file should be regarded as a signed or unsigned integer. |
endian |
The endian-ness ('“big”' or '“little”') of the target system for the file. Using '“swap”' will force swapping endian-ness. |
ipos |
iterable. If not |
Originally from the itertools
package.
An iteror reading binary chunks from the connection.
zz <- file("testbin", "wb") writeBin(1:100, zz) close(zz) it <- ihasNext(ireadBin("testbin", integer(), 10)) repeat print(nextOr(it, break)) unlink("testbin")
zz <- file("testbin", "wb") writeBin(1:100, zz) close(zz) it <- ihasNext(ireadBin("testbin", integer(), 10)) repeat print(nextOr(it, break)) unlink("testbin")
Create an iterator to read data frames from files.
ireaddf(filenames, n, start = 1, col.names, chunkSize = 1000)
ireaddf(filenames, n, start = 1, col.names, chunkSize = 1000)
filenames |
Names of files contains column data. |
n |
Maximum number of elements to read from each column file. |
start |
Element to start reading from. |
col.names |
Names of the columns. |
chunkSize |
Number of rows to read at a time. |
Originally from the itertools
package.
An iteror yielding data.frame objects with up to n
rows.
Returns an iterator over the lines of text from a connection. It is a
wrapper around the standard readLines
function.
ireadLines(con, n = 1, ...)
ireadLines(con, n = 1, ...)
con |
a connection object or a character string. |
n |
integer. The maximum number of lines to read. Negative values indicate that one should read up to the end of the connection. The default value is 1. |
... |
passed on to the |
Originally from the iterators
package.
The line reading iterator.
# create an iterator over the lines of COPYING it <- ireadLines(file.path(R.home(), "COPYING")) nextOr(it) nextOr(it) nextOr(it)
# create an iterator over the lines of COPYING it <- ireadLines(file.path(R.home(), "COPYING")) nextOr(it) nextOr(it) nextOr(it)
The iRNGStream
creates a sequence of random number seeds
that are very "far apart" (2^127 steps) in the overall random
number sequence, so that each can be used to make a parallel,
psudo-independent random iterator. This uses
parallel::nextRNGStream and the "L'Ecuyer-CMRG" generator.
iRNGStream(seed)
iRNGStream(seed)
seed |
Either a single number to be passed to |
iRNGSubStream creates seeds that are somewhat less far apart (2^76 steps), which might be used as "substream" seeds.
Originally from the itertools
package.
An iteror which produces seed values.
vector to be passed to nextRNGStream
or nextRNGSubStream
.
An iteror which yields successive seed values.
For more details on the L'Ecuyer-CMRG generator, see
vignette("parallel", package="parallel")
.
set.seed
,
nextRNGStream
,
nextRNGSubStream
global.seed <- .Random.seed rng.seeds <- iRNGStream(313) print(nextOr(rng.seeds)) print(nextOr(rng.seeds)) # create three pseudo-independent and # reproducible random number streams it1 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it2 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it3 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) all(.Random.seed == global.seed) take(it1, 5, "numeric") # 0 0 0 1 1 take(it2, 5, "numeric") # 0 1 1 1 1 take(it3, 5, "numeric") # 1 1 1 0 0 # none of this affects the global seed all(global.seed == .Random.seed) # Compute random numbers in three parallel processes with three # well-separated seeds. Requires package "foreach" library(foreach) foreach(1:3, rseed=iRNGSubStream(1970), .combine='c') %dopar% { RNGkind("L'Ecuyer-CMRG") # would be better to initialize workers only once assign('.Random.seed', rseed, pos=.GlobalEnv) runif(1) }
global.seed <- .Random.seed rng.seeds <- iRNGStream(313) print(nextOr(rng.seeds)) print(nextOr(rng.seeds)) # create three pseudo-independent and # reproducible random number streams it1 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it2 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it3 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) all(.Random.seed == global.seed) take(it1, 5, "numeric") # 0 0 0 1 1 take(it2, 5, "numeric") # 0 1 1 1 1 take(it3, 5, "numeric") # 1 1 1 0 0 # none of this affects the global seed all(global.seed == .Random.seed) # Compute random numbers in three parallel processes with three # well-separated seeds. Requires package "foreach" library(foreach) foreach(1:3, rseed=iRNGSubStream(1970), .combine='c') %dopar% { RNGkind("L'Ecuyer-CMRG") # would be better to initialize workers only once assign('.Random.seed', rseed, pos=.GlobalEnv) runif(1) }
These functions each construct an iterator that produces random numbers of various distributions. Each one is a wrapper around a base R function.
irnorm( n, mean = 0, sd = 1, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irbinom( n, size, prob, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irnbinom( n, size, prob, mu, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irpois( n, lambda, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) isample( x, size, replace = FALSE, prob = NULL, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irunif( n, min = 0, max = 1, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL )
irnorm( n, mean = 0, sd = 1, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irbinom( n, size, prob, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irnbinom( n, size, prob, mu, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irpois( n, lambda, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) isample( x, size, replace = FALSE, prob = NULL, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL ) irunif( n, min = 0, max = 1, count = Inf, independent = !missing(seed) || !missing(kind), seed = NULL, kind = NULL, normal.kind = NULL, sample.kind = NULL )
n |
How many samples to compute per call; see e.g. rnorm. |
mean |
see rnorm. |
sd |
see rnorm. |
count |
number of times that the iterator will fire. If not specified, it will fire values forever. |
independent |
If TRUE, this iterator will keep its own private
random state, so that its output is reproducible and independent
of anything else in the program; this comes at some performance
cost. Default is FALSE unless |
seed |
A specific seed value for reproducibility. If given,
|
kind |
Which random number algorithm to use; passed along to
set.seed, If given, |
normal.kind |
Passed along to set.seed. |
sample.kind |
Passed along to set.seed. |
size |
see e.g. rbinom. |
prob |
see e.g. rbinom. |
mu |
see rnbinom. |
lambda |
see rpois. |
x |
see isample. |
replace |
see isample. |
min |
see runif. |
max |
see runif. |
Originally from the iterators
package.
An iterator that is a wrapper around the corresponding random number generator function.
If you are creating multiple independent iterators, iRNGStream will create well-separated seed values, which may help avoid spurious correlations between iterators.
# create an iterator that returns three random numbers it <- irnorm(1, count = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # iterators created with a specific seed will make reproducible values it <- irunif(n=1, seed=314, kind="L'Ecuyer-CMRG") nextOr(it) # 0.4936700 nextOr(it) # 0.5103891 nextOr(it) # 0.2338745 # the iRNGStream produces a sequence of well separated seed values, rng.seeds <- iRNGStream(313) it1 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it2 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it3 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) take(it1, 5, "numeric") # 0 1 0 0 1 take(it2, 5, "numeric") # 0 1 0 0 0 take(it3, 5, "numeric") # 0 0 0 1 1
# create an iterator that returns three random numbers it <- irnorm(1, count = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # iterators created with a specific seed will make reproducible values it <- irunif(n=1, seed=314, kind="L'Ecuyer-CMRG") nextOr(it) # 0.4936700 nextOr(it) # 0.5103891 nextOr(it) # 0.2338745 # the iRNGStream produces a sequence of well separated seed values, rng.seeds <- iRNGStream(313) it1 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it2 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) it3 <- isample(c(0, 1), 1, seed=nextOr(rng.seeds)) take(it1, 5, "numeric") # 0 1 0 0 1 take(it2, 5, "numeric") # 0 1 0 0 0 take(it3, 5, "numeric") # 0 0 0 1 1
is.iteror
indicates if an object is an iteror.is.iteror
indicates if an object is an iteror.
is.iteror(x)
is.iteror(x)
x |
any object. |
TRUE if the object has class iteror
.
it <- iteror(1:3) stopifnot(is.iteror(it)) repeat { print(nextOr(it, break)) }
it <- iteror(1:3) stopifnot(is.iteror(it)) repeat { print(nextOr(it, break)) }
Constructs iterators that generate regular sequences that follow the
seq
family.
iseq( from = 1, to = NULL, by = NULL, length_out = NULL, along_with = NULL, ..., recycle = FALSE, chunkSize, chunks ) iseq_along(along_with, ...)
iseq( from = 1, to = NULL, by = NULL, length_out = NULL, along_with = NULL, ..., recycle = FALSE, chunkSize, chunks ) iseq_along(along_with, ...)
from |
the starting value of the sequence. |
to |
the end value of the sequence. |
by |
increment of the sequence. |
length_out |
desired length of the sequence. A non-negative number,
which for |
along_with |
the length of the sequence will match the length of this |
... |
Unused. |
recycle |
Whether to restart the sequence after it reaches |
chunkSize |
Optional; return this many values per call. |
chunks |
Optional; return this many chunks. |
The iseq
function generates a sequence of values beginning with
from
and ending with to
. The sequence of values between are
determined by the by
, length_out
, and along_with
arguments. The by
argument determines the step size of the sequence,
whereas length_out
and along_with
determine the length of the
sequence. If by
is not given, then it is determined by either
length_out
or along_with
. By default, neither are given, in
which case by
is set to 1 or -1, depending on whether to >
from
.
an iteror.
icount icountn
it <- iseq(from=2, to=5) unlist(as.list(it)) == 2:5
it <- iseq(from=2, to=5) unlist(as.list(it)) == 2:5
Returns an iterator that divides the data in the vector x
into the
groups defined by f
.
isplit(x, f, drop = FALSE, ...)
isplit(x, f, drop = FALSE, ...)
x |
vector or data frame of values to be split into groups. |
f |
a factor or list of factors used to categorize |
drop |
logical indicating if levels that do not occur should be dropped. |
... |
current ignored. |
Originally from the iterators
package.
The split iterator.
x <- rnorm(200) f <- factor(sample(1:10, length(x), replace = TRUE)) it <- isplit(x, f) expected <- split(x, f) for (i in expected) { actual <- nextOr(it, break) stopifnot(actual$value == i) }
x <- rnorm(200) f <- factor(sample(1:10, length(x), replace = TRUE)) it <- isplit(x, f) expected <- split(x, f) for (i in expected) { actual <- nextOr(it, break) stopifnot(actual$value == i) }
Constructs an iterator that maps a given function over an indefinite sequence
of numeric values. The input the function f
is expected to accept a
single numeric argument. The sequence of arguments passed to f
begin
with start
and are incremented by step
.
itabulate(f, start = 1, step = 1)
itabulate(f, start = 1, step = 1)
f |
the function to apply |
start |
sequence's initial value |
step |
sequence's step size |
an iterator that returns the mapped values from the sequence
it <- itabulate(f=function(x) x + 1) take(it, 4) # 2 3 4 5 it2 <- itabulate(f=function(x) x^2, start=-3) take(it2, 6) # 9 4 1 0 1 4 it3 <- itabulate(abs, start=-5, step=2) take(it3, 6) # 5 3 1 1 3 5 it4 <- itabulate(exp, start=6, step=-2) take(it4, 4) # exp(c(6, 4, 2, 0))
it <- itabulate(f=function(x) x + 1) take(it, 4) # 2 3 4 5 it2 <- itabulate(f=function(x) x^2, start=-3) take(it2, 6) # 9 4 1 0 1 4 it3 <- itabulate(abs, start=-5, step=2) take(it3, 6) # 5 3 1 1 3 5 it4 <- itabulate(exp, start=6, step=-2) take(it4, 4) # exp(c(6, 4, 2, 0))
it <- iteror(obj, ...)
is a generic constructor that creates
objects of class "iteror" from its input. An iteror outputs a
single element of a sequence each time you call
nextOr(it)
. Different iteror
methods exist for different data
types and may take different optional arguments as listed in this
page.
iteror(obj, ...) ## S3 method for class 'iter' iteror(obj, ...) ## Default S3 method: iteror(obj, ..., recycle = FALSE, chunkSize, chunks) ## S3 method for class 'connection' iteror(obj, ...)
iteror(obj, ...) ## S3 method for class 'iter' iteror(obj, ...) ## Default S3 method: iteror(obj, ..., recycle = FALSE, chunkSize, chunks) ## S3 method for class 'connection' iteror(obj, ...)
obj |
An object to iterate with. |
... |
Different |
recycle |
a boolean describing whether the iterator should reset after running through all its values. |
chunkSize |
How many elements (or slices) to include in each chunk. |
chunks |
Split the input into this many chunks. |
When called, an iteror may either return a new value or stop. The
way an iteror signals a stop is that it does whatever you write in
the argument or
. For instance you can write or=break
to exit a
loop. Summing over an iteror this way looks like:
sum <- 0 it <- iteror(iseq(0, 100, 7)) repeat { sum <- sum + nextOr(it, break) }
Another way to use the "or" argument is to give it a sentinel value;
that is, a special value that you will interpret as end of
iteration. If the result of calling nextOr
is identical()
to
the value you provided, then you know the iterator has ended. This
pattern looks like:
sum <- 0 stopped <- new.env() it <- iteror(iseq(0, 100, 7)) repeat { val <- nextOr(it, stopped) if (identical(val, stopped)) break sum <- sum + val }
(Here I'm using new.env()
as a sentinel value. In R it is
commonplace to use NULL
or NA
as a kind of sentinel value, but
that only works until you have an iterator that needs to yield NULL
itself. A safer alternative is to use a local, one-shot sentinel value;
new.env()
is ideal, as it constructs an object that is
not identical to any other object in the R session.)
Note that iteror
objects are simply functions with a class
attribute attached, and all nextOr.iteror
does is call the
function. So if you were in the mood, you could skip calling
nextOr
involving S3 dispatch and instead call the iteror
directly. If you take this approach, make sure you have called
iteror()
first to ensure that you have a true iteror
object.
sum <- 0 it <- iteror(iseq(0, 100, 7)) repeat sum <- sum + it(or=break) sum #> [1] 735
To create iterors with custom-defined behavior, see iteror.function.
an object of classes 'iteror' and 'iter'.
The method iteror.iter
wraps an iterators::iter object
and returns an iteror.
The default method iteror.default
treats obj
as a
vector to yield values from.
iteror.array iteror.function iteror.data.frame
Iterate over an array or data frame by a specified dimension.
## S3 method for class 'array' iteror( obj, ..., by = c("cell", "row", "column"), chunkSize, chunks, recycle = FALSE, drop = FALSE, rowMajor = TRUE ) ## S3 method for class 'matrix' iteror( obj, ..., by = c("cell", "row", "column"), chunkSize, chunks, recycle = FALSE, drop = FALSE, rowMajor = TRUE ) ## S3 method for class 'data.frame' iteror(obj, ..., recycle = FALSE, chunkSize, chunks, by = c("column", "row"))
## S3 method for class 'array' iteror( obj, ..., by = c("cell", "row", "column"), chunkSize, chunks, recycle = FALSE, drop = FALSE, rowMajor = TRUE ) ## S3 method for class 'matrix' iteror( obj, ..., by = c("cell", "row", "column"), chunkSize, chunks, recycle = FALSE, drop = FALSE, rowMajor = TRUE ) ## S3 method for class 'data.frame' iteror(obj, ..., recycle = FALSE, chunkSize, chunks, by = c("column", "row"))
obj |
An object to iterate over. |
... |
Undocumented. |
by |
Which dimension to slice an array or data frame by. Can be "cell", "row", "column", or numeric dimensions. |
chunkSize |
The thickness of the slice to take along the specified dimension. |
chunks |
How many slices to take. |
recycle |
If TRUE, the iteror starts over on reaching the end. |
drop |
Whether to drop the array dimensions enumerated over. |
rowMajor |
If TRUE, will return slices in order with the first indices varying fastest (same as in i_enumerate). |
an iteror yielding from obj
along the specified dimensions.
l <- iteror(letters, chunkSize=7) as.list(l) a <- array(1:8, c(2, 2, 2)) # iterate over all the slices it <- iteror(a, by=3) as.list(it) # iterate over all the columns of each slice it <- iteror(a, by=c(2, 3)) as.list(it) # iterate over all the rows of each slice it <- iteror(a, by=c(1, 3)) as.list(it)
l <- iteror(letters, chunkSize=7) as.list(l) a <- array(1:8, c(2, 2, 2)) # iterate over all the slices it <- iteror(a, by=3) as.list(it) # iterate over all the columns of each slice it <- iteror(a, by=c(2, 3)) as.list(it) # iterate over all the rows of each slice it <- iteror(a, by=c(1, 3)) as.list(it)
Pass obj
a function that has a first argument named "or". In
writing this function, you can maintain state by using enclosed
variables and update using <<-
, Whatever value obj()
returns is
the next element of the iteror. Treat argument or
as a lazy value;
do not touch it until until you need to signal end of iteration;
to signal end of iteration, force and immediately return or
.
## S3 method for class ''function'' iteror(obj, ..., catch, sentinel, count)
## S3 method for class ''function'' iteror(obj, ..., catch, sentinel, count)
obj |
A function. It should have having an argument named "or" |
... |
Undocumented. |
catch |
If |
sentinel |
If |
count |
If |
You can also provide obj
a simple function of no arguments, as
long as you specify one of catch
, sentinel
, or count
to specify
how to detect end of iteration.
An object of mode "function" and class "iteror".
An iteror which calls the given function to produce values.
# an iterator that counts from start to stop irange <- function(from=1, to=Inf) { current <- from iteror(function(or) { if (current > to) { return(or) } else { tmp <- current current <<- current + 1 tmp } }) } it <- irange(5, 10) as.vector(it, "numeric") # an endless random number generator irand <- function(min, max) { iteror(function() runif(1, min=min, max=max), count=Inf) } take(irand(5, 10), 10)
# an iterator that counts from start to stop irange <- function(from=1, to=Inf) { current <- from iteror(function(or) { if (current > to) { return(or) } else { tmp <- current current <<- current + 1 tmp } }) } it <- irange(5, 10) as.vector(it, "numeric") # an endless random number generator irand <- function(min, max) { iteror(function() runif(1, min=min, max=max), count=Inf) } take(irand(5, 10), 10)
The makeIwrapper
function wraps an R function to produce an
iterator constructor. It is used to construct random sampling
iterators in this package; for instance irnorm
is defined as
irnorm <- makeIwrapper(rnorm)
.
makeIwrapper(FUN)
makeIwrapper(FUN)
FUN |
a function that generates different values each time it is called; typically one of the standard random number generator functions. |
The resulting iterator constructors all take an optional
count
argument which specifies the number of times the
resulting iterator should fire. They also have an argument
independent
which enables independent tracking of the random
number seed. The isample
function is an example of one such
iterator constructoe (as are irnorm
, irunif
, etc.).
Original version appeared in the iterators
package.
An iterator that is a wrapper around the corresponding function.
# create an iterator maker for the sample function mysample <- makeIwrapper(sample) # use this iterator maker to generate an iterator that will generate three five # member samples from the sequence 1:100 it <- mysample(1:100, 5, count = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # NULL
# create an iterator maker for the sample function mysample <- makeIwrapper(sample) # use this iterator maker to generate an iterator that will generate three five # member samples from the sequence 1:100 it <- mysample(1:100, 5, count = 3) nextOr(it) nextOr(it) nextOr(it) nextOr(it, NULL) # NULL
Retreive the next element from an iteror.
nextOr(obj, or, ...)
nextOr(obj, or, ...)
obj |
An iteror. |
or |
If the iterator has reached its end, this argument will be forced and returned. |
... |
Other arguments may be used by specific iterors. |
Either the next value of iteror
, or the value of or
.
Returns the n
th item of an iteror
after advancing the
iteror n
steps ahead. If the iteror
is entirely consumed,
the argument or
is returned instead. That is, if either n >
length(iteror)
or n
is 0, then the iteror
is consumed.
nth(obj, n, or, ...)
nth(obj, n, or, ...)
obj |
an iterable. |
n |
The index of the desired element to return. |
or |
If the iteror finishes before retuning |
... |
passed along to iteror constructor. |
The nth element of the iteror or the result of forcing or
.
take consume collect
it <- iteror(1:10) # Returns 5 nth(it, 5, NA) it2 <- iteror(letters) # Returns 'e' nth(it2, 5, NA) it3 <- iteror(letters) # Returns default value of NA nth(it3, 42, NA) it4 <- iteror(letters) # Returns default value of "foo" nth(it4, 42, or="foo")
it <- iteror(1:10) # Returns 5 nth(it, 5, NA) it2 <- iteror(letters) # Returns 'e' nth(it2, 5, NA) it3 <- iteror(letters) # Returns default value of NA nth(it3, 42, NA) it4 <- iteror(letters) # Returns default value of "foo" nth(it4, 42, or="foo")
Returns the number of elements from an iterable object that
evaluate to TRUE
.
quantify(obj, ...)
quantify(obj, ...)
obj |
an iterable object |
... |
further arguments passed to iteror. |
the number of TRUE
elements
reduce
it <- iteror(c(TRUE, FALSE, TRUE)) quantify(it) # 2 set.seed(42) x <- sample(c(TRUE, FALSE), size=10, replace=TRUE) quantify(x) # Equivalent to sum(x)
it <- iteror(c(TRUE, FALSE, TRUE)) quantify(it) # 2 set.seed(42) x <- sample(c(TRUE, FALSE), size=10, replace=TRUE) quantify(x) # Equivalent to sum(x)
This requires the reticulate
package to be installed.
## S3 method for class 'iteror' r_to_py(x, convert = FALSE, ...) ## S3 method for class 'python.builtin.object' iteror(obj, ...)
## S3 method for class 'iteror' r_to_py(x, convert = FALSE, ...) ## S3 method for class 'python.builtin.object' iteror(obj, ...)
x |
An iterable object. |
convert |
does nothing. |
... |
Passed along to |
obj |
A Python object (as viewed by package |
r_to_py(it)
returns a Python iterator.
Method iteror.python.builtin.object
returns an iteror.
pit <- reticulate::r_to_py(iseq(2, 11, 5)) reticulate::iter_next(pit, NULL) reticulate::iter_next(pit, NULL) reticulate::iter_next(pit, NULL) # create an R iterator and ask Python to sum it triangulars <- icount() |> i_accum() |> i_limit(10) builtins <- reticulate::import_builtins() builtins$sum(triangulars) # r_to_py is called automatically # create a generator in Python and sum it in R pit <- reticulate::py_eval("(n for n in range(1, 25) if n % 3 == 0)") sum(iteror(pit))
pit <- reticulate::r_to_py(iseq(2, 11, 5)) reticulate::iter_next(pit, NULL) reticulate::iter_next(pit, NULL) reticulate::iter_next(pit, NULL) # create an R iterator and ask Python to sum it triangulars <- icount() |> i_accum() |> i_limit(10) builtins <- reticulate::import_builtins() builtins$sum(triangulars) # r_to_py is called automatically # create a generator in Python and sum it in R pit <- reticulate::py_eval("(n for n in range(1, 25) if n % 3 == 0)") sum(iteror(pit))
The record
function records the values issued by a specified
iterator to a file or connection object. The ireplay
function
returns an iterator that will replay those values. This is useful for
iterating concurrently over multiple, large matrices or data frames that you
can't keep in memory at the same time. These large objects can be recorded
to files one at a time, and then be replayed concurrently using minimal
memory.
record(iterable, con, ...)
record(iterable, con, ...)
iterable |
The iterable to record to the file. |
con |
A file path or open connection. |
... |
passed along to |
Originally from the itertools
package.
NULL, invisibly.
suppressMessages(library(foreach)) m1 <- matrix(rnorm(70), 7, 10) f1 <- tempfile() record(iteror(m1, by='row', chunkSize=3), f1) m2 <- matrix(1:50, 10, 5) f2 <- tempfile() record(iteror(m2, by='column', chunkSize=3), f2) # Perform a simple out-of-core matrix multiply p <- foreach(col=ireplay(f2), .combine='cbind') %:% foreach(row=ireplay(f1), .combine='rbind') %do% { row %*% col } dimnames(p) <- NULL print(p) all.equal(p, m1 %*% m2) unlink(c(f1, f2))
suppressMessages(library(foreach)) m1 <- matrix(rnorm(70), 7, 10) f1 <- tempfile() record(iteror(m1, by='row', chunkSize=3), f1) m2 <- matrix(1:50, 10, 5) f2 <- tempfile() record(iteror(m2, by='column', chunkSize=3), f2) # Perform a simple out-of-core matrix multiply p <- foreach(col=ireplay(f2), .combine='cbind') %:% foreach(row=ireplay(f1), .combine='rbind') %do% { row %*% col } dimnames(p) <- NULL print(p) all.equal(p, m1 %*% m2) unlink(c(f1, f2))
reduce(obj, fun)
applies a 2-argument function fun
between
successive elements of obj. For example if fun
is +
,
reduce(it,
+, init=0)
computes 0 + nextElem(it) + nextElem(it) + nextElem(it) + ...
until the iterator finishes,
and returns the final value.
i_accum(obj)
returns the iterator containing
each intermediate result. The default settings
produce a cumulative sum.
sum.iteror(it)
is equivalent to reduce(it, `+`)
prod.iteror(it)
is equivalent to reduce(it, `*`)
.
reduce(obj, fun = `+`, init = 0, ...) ## S3 method for class 'iteror' reduce(obj, fun = `+`, init = 0, ...) i_accum(obj, fun = `+`, init = 0, ...) ## S3 method for class 'iteror' sum(..., na.rm = FALSE) ## S3 method for class 'iteror' prod(..., na.rm = FALSE)
reduce(obj, fun = `+`, init = 0, ...) ## S3 method for class 'iteror' reduce(obj, fun = `+`, init = 0, ...) i_accum(obj, fun = `+`, init = 0, ...) ## S3 method for class 'iteror' sum(..., na.rm = FALSE) ## S3 method for class 'iteror' prod(..., na.rm = FALSE)
obj |
an iterable object |
fun |
A function of as least two arguments. |
init |
A starting value. |
... |
Extra parameters will be passed to each call to |
na.rm |
Whether to drop NA values when computing sum or prod. |
The result of accumulation.
Peter Meilstrup
it <- icount(5) total <- reduce(it, `+`) # 15 it <- icount(5) reduce(it, paste0, "") # "12345" it <- icount(5) reduce(it, `*`, init=1) # 120 # triangular numbers: 1, 1+2, 1+2+3, ... take(i_accum(icount()), 10, 'numeric')
it <- icount(5) total <- reduce(it, `+`) # 15 it <- icount(5) reduce(it, paste0, "") # "12345" it <- icount(5) reduce(it, `*`, init=1) # 120 # triangular numbers: 1, 1+2, 1+2+3, ... take(i_accum(icount()), 10, 'numeric')
Returns the first n
elements of an iterable object
as a list.
If n
is larger than the number of elements in object
, the
entire iterator is consumed.
take(obj, n = 1, mode = "list", ...) ## Default S3 method: take(obj, n = 1, mode = "list", ...) ## S3 method for class 'iteror' take(obj, n = 1, mode = "list", ...)
take(obj, n = 1, mode = "list", ...) ## Default S3 method: take(obj, n = 1, mode = "list", ...) ## S3 method for class 'iteror' take(obj, n = 1, mode = "list", ...)
obj |
An iterable object. |
n |
The maximum number of elements to extract from the iteror. |
mode |
The mode of vector to return. |
... |
Further arguments may be passed along to the iteror constructor. |
A function take
first appeared in package itertools2
.
It is basically an alias for as.list but defaults to n=1.
a list of the first n
items of the iterable
obj
concat as.vector.iteror
as.vector.iteror
take(1:10, 3) # 1 2 3 take(icount(), 10) # 1:10 take(icount(5), 10) # 1 2 3 4 5
take(1:10, 3) # 1 2 3 take(icount(), 10) # 1:10 take(icount(5), 10) # 1 2 3 4 5