Skip to content

Commit bcd9d8e

Browse files
committed
renamed bycol to byrow; fixed that gen.named.(vector|list) can be used as a inner expression of other gen.-functions
1 parent 4f2706f commit bcd9d8e

File tree

8 files changed

+109
-47
lines changed

8 files changed

+109
-47
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: listcompr
22
Version: 0.2.5
3-
Date: 2021-05-08
3+
Date: 2021-05-17
44
Title: List Comprehension for R
55
Author: Patrick Roocks <[email protected]>
66
Maintainer: Patrick Roocks <[email protected]>

NEWS.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# listcompr 0.2.5
22

3-
* added `bycol` parameter to `gen.(named).(data.frame|matrix)` which applies the Cartesian product by column to the expression (WIP: documentation)
3+
* added `byrow` parameter to `gen.(named).(data.frame|matrix)` which applies the Cartesian product by column to the expression
4+
* fixed that `gen.named.(vector|list)` can be used as a inner expression of other `gen.`-functions
45

56
# listcompr 0.2.4
67

R/eval.r

+17-16
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,16 @@ get_vars_and_conditions <- function(l, is_var, is_cond, ctx) {
246246
}
247247

248248
# searches for 2-dim matrix without names/conditions, e.g. gen.matrix(i+j, i=1:3, j=1:4)
249-
check_2d_matrix <- function(first_row, is_by_col, vars, conds, parent_frame) {
249+
check_2d_matrix <- function(first_row, is_by_row, vars, conds, parent_frame) {
250250
if (!( is.null(names(first_row))
251251
&& length(first_row) == 1
252252
&& length(vars) == 2 && length(conds) == 0)) return(NULL)
253253

254-
rowindex <- if (is_by_col) 2 else 1
254+
rowindex <- if (is_by_row) 2 else 1
255255
nrow <- tryCatch(eval(vars[[rowindex]], parent_frame), error = function(e) NULL)
256256
if (is.null(row)) return(NULL)
257257

258-
colindex <- if (is_by_col) 1 else 2
258+
colindex <- if (is_by_row) 1 else 2
259259
ncol <- tryCatch(eval(vars[[colindex]], parent_frame), error = function(e) NULL)
260260
if (is.null(ncol)) return(NULL)
261261

@@ -285,9 +285,9 @@ fold.or <- function(lst) {
285285

286286
# ----- Main functions (called by interface) -----
287287

288-
OUTPUT_FORMAT <- list(LST = 1, VEC = 2, LST_EXPR = 3, VEC_EXPR = 4, DF = 5, DF_COL = 6, MTX = 7, MTX_COL = 8)
288+
OUTPUT_FORMAT <- list(LST = 1, VEC = 2, LST_EXPR = 3, VEC_EXPR = 4, DF = 5, DF_ROW = 6, MTX = 7, MTX_ROW = 8)
289289

290-
gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
290+
gen_list_internal <- function(expr, l, output_format, name_str_expr, parent_frame) {
291291

292292
# * preliminary checks, find vars/conditions
293293

@@ -307,9 +307,9 @@ gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
307307
is_format_expr <- output_format %in% c(OUTPUT_FORMAT[["LST_EXPR"]], OUTPUT_FORMAT[["VEC_EXPR"]])
308308
is_format_vec <- output_format %in% c(OUTPUT_FORMAT[["VEC"]], OUTPUT_FORMAT[["VEC_EXPR"]])
309309
is_format_lst <- output_format %in% c(OUTPUT_FORMAT[["LST"]], OUTPUT_FORMAT[["LST_EXPR"]])
310-
is_format_mtx <- output_format %in% c(OUTPUT_FORMAT[["MTX"]], OUTPUT_FORMAT[["MTX_COL"]])
311-
is_format_df <- output_format %in% c(OUTPUT_FORMAT[["DF"]], OUTPUT_FORMAT[["DF_COL"]])
312-
is_by_col <- output_format %in% c(OUTPUT_FORMAT[["MTX_COL"]], OUTPUT_FORMAT[["DF_COL"]])
310+
is_format_mtx <- output_format %in% c(OUTPUT_FORMAT[["MTX"]], OUTPUT_FORMAT[["MTX_ROW"]])
311+
is_format_df <- output_format %in% c(OUTPUT_FORMAT[["DF"]], OUTPUT_FORMAT[["DF_ROW"]])
312+
is_by_row <- output_format %in% c(OUTPUT_FORMAT[["MTX_ROW"]], OUTPUT_FORMAT[["DF_ROW"]])
313313

314314
# * Expansions
315315

@@ -318,9 +318,10 @@ gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
318318
expr <- res[["expr"]]
319319
vars <- res[["vars"]]
320320

321-
has_row_names <- !is.null(name_str)
321+
has_row_names <- !is.null(name_str_expr)
322322
if (has_row_names) { # for named list/vectors/...
323-
res <- expand_expr(name_str, vars, ctx)
323+
if (is.symbol(name_str_expr)) name_str_expr <- eval(name_str_expr, parent_frame)
324+
res <- expand_expr(name_str_expr, vars, ctx)
324325
name_str_expr <- res[["expr"]]
325326
vars <- res[["vars"]]
326327
}
@@ -342,7 +343,7 @@ gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
342343
}
343344

344345
if (has_row_names) {
345-
name_vec <- vapply(1:nrow(cartesian_df), function(i) eval(name_str_expr, cartesian_df[i,,drop=FALSE], parent_frame), '')
346+
name_vec <- vapply(1:nrow(cartesian_df), function(i) eval(name_str_expr, cartesian_df[i,,drop=FALSE], parent_frame), "")
346347
}
347348

348349
# * Apply expression and return
@@ -352,15 +353,15 @@ gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
352353
} else {
353354
rv <- lapply(1:nrow(cartesian_df), function(i) eval(expr, cartesian_df[i,,drop=FALSE], parent_frame))
354355
}
355-
if (!is.null(name_str)) names(rv) <- name_vec
356+
if (has_row_names) names(rv) <- name_vec
356357
return(rv)
357358

358359
} else if (is_format_expr) {
359360
rv <- if (is_format_vec) quote(c()) else quote(list())
360361
for (i in 1:nrow(cartesian_df)) {
361362
rv[[i+1]] <- eval_partial(expr, cartesian_df[i,,drop=FALSE])
362363
}
363-
if (!is.null(name_str)) names(rv) <- c("", name_vec)
364+
if (has_row_names) names(rv) <- c("", name_vec)
364365
return(rv)
365366

366367
} else if (is_format_df || is_format_mtx) {
@@ -370,15 +371,15 @@ gen_list_internal <- function(expr, l, output_format, name_str, parent_frame) {
370371
rv_list <- lapply(1:nrow(cartesian_df), function(i) eval(expr, cartesian_df[i,,drop=FALSE], parent_frame))
371372
if (has_row_names) names(rv_list) <- name_vec
372373
rv_list_begin <- rv_list[[1]]
373-
rv_list <- do.call((if (is_by_col) "cbind" else "rbind"), rv_list)
374+
rv_list <- do.call((if (is_by_row) "cbind" else "rbind"), rv_list)
374375
if (output_format == OUTPUT_FORMAT[["DF"]]) {
375376
return(as.data.frame(rv_list, stringsAsFactors = FALSE))
376377
} else { # matrix
377-
res_mtx <- if (!has_row_names) check_2d_matrix(rv_list_begin, is_by_col, vars, conds, parent_frame) else NULL
378+
res_mtx <- if (!has_row_names) check_2d_matrix(rv_list_begin, is_by_row, vars, conds, parent_frame) else NULL
378379
if (is.null(res_mtx)) {
379380
return(as.matrix(rv_list))
380381
} else {
381-
return(matrix(rv_list, nrow = res_mtx[["nrow"]], ncol = res_mtx[["ncol"]], byrow = is_by_col))
382+
return(matrix(rv_list, nrow = res_mtx[["nrow"]], ncol = res_mtx[["ncol"]], byrow = is_by_row))
382383
}
383384
}
384385
}

R/gen-list.r

+31-15
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@
1717
#' \item For \code{gen.vector} a value (i.e., a vector of length 1) is expected.
1818
#' \item For \code{gen.data.frame} a (named) vector or list is expected which describes one row of the data frame.
1919
#' \item For \code{gen.matrix} either a (named) vector/list (like \code{gen.data.frame}) or a scalar is expected.
20-
#' In the latter case we expect exactly two variables (inducing rows/columns) within the \code{...} arguments.
20+
#' In the latter case we expect exactly two variables (inducing rows and columns where the order depends on \code{byrow}) within the \code{...} arguments.
2121
#' }
2222
#' Within \code{expr} it is allowed to use functions and predefined constants from the parent environment.
2323
#' @param ... Arbitrary many variable ranges and conditions.
2424
#' For all free variables occurring in \code{expr} a range must be assigned, e.g., \code{x = 1:3, y = 1:5} for an expression \code{x + y}.
2525
#' At least one variable range is required.
2626
#' The ranges may depend on each other, e.g., \code{x = 1:3, y = x:3} or a substitution like \code{x = 1:3, y = 2 * x} is allowed.
27-
#' The generated values can be further restricted by conditions (like \code{x <= y}).
28-
#'
27+
#' The generated values can be further restricted by conditions like \code{x <= y}.
28+
#' @param byrow Logical. If \code{FALSE} (the default), the elements of a vector within \code{expr} are taken as columns.
29+
#' Otherwise, they are taken as rows.
30+
#'
2931
#' @return
3032
#'
31-
#' The result of \code{gen.list} is a list (a vector for \code{gen.vector}) containing an entry for each combination of the free variables (i.e., the Cartesian product), where all the free variables in \code{expr} are substituted.
33+
#' The result of \code{gen.list} is a list (a vector for \code{gen.vector}) containing an entry for each combination of the free variables (i.e., the Cartesian product),
34+
#' where all the free variables in \code{expr} are substituted.
3235
#' The function \code{gen.vector} returns a vector while \code{gen.list} may contain also more complex substructures (like vectors or lists).
3336
#'
3437
#' The output of \code{gen.data.frame} is a data frame where each substituted \code{expr} entry is one row.
@@ -42,8 +45,10 @@
4245
#' Each substituted \code{expr} entry is one row of the matrix.
4346
#' In contrast to \code{gen.data.frame}, column names are not auto-generated, e.g., \code{gen.matrix(c(a_1, a_2), a_ = 1:2)} is an unnamed matrix.
4447
#' If the \code{expr} argument has explicit names (e.g., \code{c(a_1 = a_1, a_2 = a_2)}), these column names are assigned to the resulting matrix.
45-
#' \item It's a matrix where the rows/columns are induced by the first/second variable, if \code{expr} is a scalar, and no names or conditions are given.
48+
#' \item It's a matrix where the rows and columns are induced by the two variables within \code{...}, if \code{expr} is a scalar, and no names or conditions are given.
49+
#' If \code{byrow} is \code{FALSE}, the second variable (i.e., the inner loop) refers to the columns, otherwise it refers to the rows.
4650
#' For instance, \code{gen.matrix(i + j, i = 1:3, j = 1:2)} is a matrix with 3 rows and 2 columns.
51+
#' For \code{gen.matrix(i + j, i = 1:3, j = 1:2, byrow = TRUE)} we get 2 rows and 3 columns.
4752
#' }
4853
#'
4954
#' 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.
@@ -87,8 +92,9 @@
8792
#' For instance, \code{"var{x + 1}_{{a}}"} is transformed into \code{"var2_{a}"} for \code{x = 1}.
8893
#'
8994
#'
90-
#' @seealso \code{\link{gen.list.expr}} to generate expressions to be evaluated later,
91-
#' \code{\link{gen.named.list.expr}} to generate named structures,
95+
#' @seealso
96+
#' \code{\link{gen.named.list}} to generate named structures,
97+
#' \code{\link{gen.list.expr}} to generate expressions to be evaluated later,
9298
#' \code{\link{gen.logical.and}} to generate logical and/or conditions,
9399
#' and \link{listcompr} for an overview of all list comprehension functions.
94100
#'
@@ -135,18 +141,18 @@ gen.vector <- function(expr, ...) {
135141

136142
#' @rdname gen.list
137143
#' @export
138-
gen.data.frame <- function(expr, ..., bycol = FALSE) {
144+
gen.data.frame <- function(expr, ..., byrow = FALSE) {
139145
l <- substitute(list(...))
140146
expr <- substitute(expr)
141-
return(gen_list_internal(expr, l, if (bycol) OUTPUT_FORMAT[["DF_COL"]] else OUTPUT_FORMAT[["DF"]], NULL, parent.frame()))
147+
return(gen_list_internal(expr, l, if (byrow) OUTPUT_FORMAT[["DF_ROW"]] else OUTPUT_FORMAT[["DF"]], NULL, parent.frame()))
142148
}
143149

144150
#' @rdname gen.list
145151
#' @export
146-
gen.matrix <- function(expr, ..., bycol = FALSE) {
152+
gen.matrix <- function(expr, ..., byrow = FALSE) {
147153
l <- substitute(list(...))
148154
expr <- substitute(expr)
149-
return(gen_list_internal(expr, l, if (bycol) OUTPUT_FORMAT[["MTX_COL"]] else OUTPUT_FORMAT[["MTX"]], NULL, parent.frame()))
155+
return(gen_list_internal(expr, l, if (byrow) OUTPUT_FORMAT[["MTX_ROW"]] else OUTPUT_FORMAT[["MTX"]], NULL, parent.frame()))
150156
}
151157

152158
# ----- Named Structures -----
@@ -165,6 +171,8 @@ gen.matrix <- function(expr, ..., bycol = FALSE) {
165171
#' For instance, \code{"var{x + 1}_{{a}}"} is transformed into \code{"var2_{a}"} for \code{x = 1}.
166172
#' @param expr A base expression containing free variables which is evaluated for all combinations of variables.
167173
#' @param ... Arbitrary many variable ranges and conditions.
174+
#' @param byrow Logical. If \code{FALSE} (the default), the elements of an \code{expr} vector are taken as columns.
175+
#' Otherwise, they are taken as rows.
168176
#'
169177
#' @details
170178
#'
@@ -189,9 +197,14 @@ gen.matrix <- function(expr, ..., bycol = FALSE) {
189197
#' # matrix with named columns and rows
190198
#' gen.named.matrix("row{i}", gen.named.vector("col{j}", i+j, j = 1:3), i = 1:3)
191199
#'
200+
#' # a matrix where the expression refers to the rows and not the columns
201+
#' gen.named.matrix("col{i}", c(row1 = i, row2 = 10 * i, row3 = 100 * i), i = 1:10,
202+
#' byrow = TRUE)
203+
#'
192204
#' @export
193205
gen.named.list <- function(str, expr, ...) {
194206
l <- substitute(list(...))
207+
str <- substitute(str)
195208
expr <- substitute(expr)
196209
return(gen_list_internal(expr, l, OUTPUT_FORMAT[["LST"]], str, parent.frame()))
197210
}
@@ -200,24 +213,27 @@ gen.named.list <- function(str, expr, ...) {
200213
#' @export
201214
gen.named.vector <- function(str, expr, ...) {
202215
l <- substitute(list(...))
216+
str <- substitute(str)
203217
expr <- substitute(expr)
204218
return(gen_list_internal(expr, l, OUTPUT_FORMAT[["VEC"]], str, parent.frame()))
205219
}
206220

207221
#' @rdname gen.named.list
208222
#' @export
209-
gen.named.data.frame <- function(str, expr, ..., bycol = FALSE) {
223+
gen.named.data.frame <- function(str, expr, ..., byrow = FALSE) {
210224
l <- substitute(list(...))
225+
str <- substitute(str)
211226
expr <- substitute(expr)
212-
return(gen_list_internal(expr, l, if (bycol) OUTPUT_FORMAT[["DF_COL"]] else OUTPUT_FORMAT[["DF"]], str, parent.frame()))
227+
return(gen_list_internal(expr, l, if (byrow) OUTPUT_FORMAT[["DF_ROW"]] else OUTPUT_FORMAT[["DF"]], str, parent.frame()))
213228
}
214229

215230
#' @rdname gen.named.list
216231
#' @export
217-
gen.named.matrix <- function(str, expr, ..., bycol = FALSE) {
232+
gen.named.matrix <- function(str, expr, ..., byrow = FALSE) {
218233
l <- substitute(list(...))
234+
str <- substitute(str)
219235
expr <- substitute(expr)
220-
return(gen_list_internal(expr, l, if (bycol) OUTPUT_FORMAT[["MTX_COL"]] else OUTPUT_FORMAT[["MTX"]], str, parent.frame()))
236+
return(gen_list_internal(expr, l, if (byrow) OUTPUT_FORMAT[["MTX_ROW"]] else OUTPUT_FORMAT[["MTX"]], str, parent.frame()))
221237
}
222238

223239
# ----- Expressions -----

man/gen.list.Rd

+14-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/gen.named.list.Rd

+9-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)