listcompr (version 0.4.0)

gen.list: Generate Lists, Vectors, Data Frames and Matrices with List Comprehension

Description

Functions to transform a base expression containing free variables into a list, a vector, a data frame, or a matrix based on variable ranges and additional conditions.

Usage

gen.list(.expr, ...)

gen.vector(.expr, ...)

gen.data.frame(.expr, ..., byrow = FALSE)

gen.matrix(.expr, ..., byrow = FALSE)

Arguments

.expr

A base expression containing free variables which is evaluated for all combinations of variables, where the combinations of variables are given by the ranges and conditions (see ... parameters).

Expected structure of .expr:

  • For gen.list it may have arbitrary structure (including a list).

  • For gen.vector a value (i.e., a vector of length 1) is expected.

  • For gen.data.frame a (named) vector or list is expected which describes exactly one row of the data frame. Use list(name = val) if val is a non-fundamental type like difftime.

  • For gen.matrix either a (named) vector/list (like gen.data.frame) or a scalar is expected. In the first case, we expect the same as for gen.data.frame. In the latter case we expect exactly two variables (inducing rows and columns where the order depends on byrow) within the ... arguments.

Within .expr it is allowed to use functions and predefined constants from the parent environment.

...

Arbitrary many variable ranges and conditions. For all free variables occurring in .expr a range must be assigned, e.g., x = 1:3, y = 1:5 for an expression x + y. At least one variable range is required. The ranges may depend on each other, e.g., x = 1:3, y = x:3 or a substitution like x = 1:3, y = 2 * x is allowed. The generated values can be further restricted by conditions like x <= y.

byrow

Logical. If FALSE (the default), the elements of a vector within .expr are taken as columns. Otherwise, they are taken as rows.

Value

The result of gen.list is a list (a vector for gen.vector) containing an entry for each combination of the free variables (i.e., the Cartesian product), where all the free variables in .expr are substituted. The function gen.vector returns a vector while gen.list may contain also more complex substructures (like vectors or lists).

The output of gen.data.frame is a data frame where each substituted .expr entry is one row. The base expression .expr should contain a (named) vector or list, such that each entry of this vector becomes a column of the returned data frame. If the vector contains a single literal without a name, this is taken as column name. For instance, gen.data.frame(a, a = 1:5) returns the same as gen.data.frame(c(a = a), a = 1:5). Default names 'V1', 'V2', ... are used, if no names are given and names can't be automatically detected.

The result of gen.matrix:

  • It's similar to gen.data.frame, if .expr evaluates to a vector of length > 1, or row/column names are given. Each substituted .expr entry is one row of the matrix. In contrast to gen.data.frame, column names are not auto-generated, e.g., gen.matrix(c(a_1, a_2), a_ = 1:2) is an unnamed matrix. If the .expr argument has explicit names (e.g., c(a_1 = a_1, a_2 = a_2)), these column names are assigned to the resulting matrix.

  • It's a matrix where the rows and columns are induced by the two variables within ..., if .expr is a scalar, and no names or conditions are given. If byrow is FALSE, the second variable (i.e., the inner loop) refers to the columns, otherwise it refers to the rows. For instance, gen.matrix(i + j, i = 1:3, j = 1:2) is a matrix with 3 rows and 2 columns. For gen.matrix(i + j, i = 1:3, j = 1:2, byrow = TRUE) we get 2 rows and 3 columns.

All expressions and conditions are applied to each combination of the free variables separately, i.e., they are applied row-wise and not vector-wise. For instance, the term sum(x,y) (within .expr or a condition) is equivalent to x+y.

Indices for variables

A range for a variable ending with an underscore (like x_) defines a set of ranges affecting all variables named {varname}_{index}, e.g. x_1. For instance, in gen.vector(x_1 + x_2 + x_3, x_ = 1:5) the variables x_1, x_2, x_3 are all ranging in 1:5. This can be overwritten for each single x_i, e.g., an additional argument x_3 = 1:3 assigns the range 1:3 to x_3 while x_1 and x_2 keep the range 1:5. A group of indexed variables is kept always sorted according to the position of the main variable {varname}_. For instance, the two following statements produce the same results:

  • gen.vector(x_1 + x_2 + a, x_ = 1:5, a = 1:2, x_1 = 1:2)

  • gen.vector(x_1 + x_2 + a, x_1 = 1:2, x_2 = 1:5, a = 1:2)

Folded expressions

Expressions and conditions support a ...-notation which works as follows:

  • A vector like c(x_1, ..., x_4) is a shortcut for c(x_1, x_2, x_3, x_4).

  • A named vector like c(a_1 = x_1, ..., a_3 = x_3) is a shortcut for c(a_1 = x_1, a_2 = x_2, a_3 = x_3).

  • A n-ary function argument like sum(x_1, ..., x_4) is a shortcut for sum(x_1, x_2, x_3, x_4).

  • Repeated expressions of binary operators can be abbreviated with the ... expressions as follows: x_1 + ... + x_4 is a shortcut for x_1 + x_2 + x_3 + x_4. Note that, due to operator precedence, 1 + x_1 + ... + x_4 will not work, but 1 + (x_1 + ... + x_4) works as expected.

  • For non-commutative operators, x_1 - ... - x_4 is a shortcut for x_1 - x_2 - x_3 - x_4 which is evaluated as ((x_1 - x_2) - x_3) - x_4.

The conditions may contain itself list comprehension expressions, e.g., gen.logical.and to compose and-connected logical expressions.

Character patterns

In expression there may occur characters with {}-placeholders. The content of these placeholders is evaluated like any other part of an expression and converted to a character. For example, "a{x}" is transformed into "a1" for x = 1. Double brackets are transformed into a single bracket without evaluating the inner expression. For instance, "var{x + 1}_{{a}}" is transformed into "var2_{a}" for x = 1.

See Also

gen.named.list to generate named structures, gen.list.expr to generate expressions to be evaluated later, gen.logical.and to generate logical and/or conditions, and listcompr for an overview of all list comprehension functions.

Examples

Run this code
# NOT RUN {
# Sum of 1:x
gen.vector(sum(1:x), x = 1:10)

# Same as above, but return as text
gen.list("sum of 1 to {x} is {sum(1:x)}", x = 1:5)

# A list containing vectors [1], [1, 2], [1, 2, 3], ...
gen.list(gen.vector(i, i = 1:n), n = 1:10)

# A data frame of tuples (x_1, x_2, x_3) summing up to 10
gen.data.frame(c(x_1, ..., x_3), x_ = 1:10, x_1 + ... + x_3 == 10)

# Same as above, but restrict to ascending tuples with x_i <= x_(i+1)
gen.data.frame(c(x_1, ..., x_3), x_1 = 1:10, x_2 = x_1:10, x_3 = x_2:10,
               x_1 + ... + x_3 == 10)

# A data frame containing the numbers in 2:20, the sum of their divisors
# and a flag if they are "perfect" (sum of divisors equals the number)
gen.data.frame(list(n, sumdiv, perfect = (n == sumdiv)), n = 2:20, 
               sumdiv = sum(gen.vector(x, x = 1:(n-1), n %% x == 0)))
               
# A diagonal matrix with (1, ..., 5) on the diagonal
gen.matrix(if (i == j) i else 0, i = 1:5, j = 1:5)

# }

Run the code above in your browser using DataLab