Skip to content

Commit f44de57

Browse files
committed
Add new function 'to_df' which is the same as 'to_list' but return data.frame (issue #2)
1 parent e4d0e98 commit f44de57

File tree

6 files changed

+94
-1
lines changed

6 files changed

+94
-1
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: comprehenr
22
Type: Package
33
Title: List Comprehensions
4-
Version: 0.6.9
4+
Version: 0.6.10
55
Maintainer: Gregory Demin <gdemin@gmail.com>
66
Authors@R: person("Gregory", "Demin", email = "gdemin@gmail.com",
77
role = c("aut", "cre"))

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export(exclude)
66
export(lag_list)
77
export(mark)
88
export(numerate)
9+
export(to_df)
910
export(to_list)
1011
export(to_vec)
1112
export(unmark)

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
0.6.10 (31-01-2021)
2+
================
3+
* add new function 'to_df' which combine result of list comprehension to data.frame (issue #2)
4+
15
0.6.9 (18-01-2021)
26
================
37
* fix bug with nested 'to_list'/'to_vec'/'alter' (issue #1)

R/to_list.R

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ SPECIAL_FUNCTIONS = expression(
2121
#' `repeat`. You can iterate over multiple lists if you provide several
2222
#' loop variables in backticks. See examples.
2323
#' - `to_vec` is the same as 'to_list' but return vector. See examples.
24+
#' - `to_df` is the same as 'to_list' but return data.frame. All elements of
25+
#' resulted list will be converted to data.frame and combined via `rbind`.
2426
#' - `alter` returns the same type as its argument but with modified
2527
#' elements. It is useful for altering existing data.frames or lists. See
2628
#' examples.
@@ -30,6 +32,7 @@ SPECIAL_FUNCTIONS = expression(
3032
#' @param expr expression which starts with `for`, `while` or `repeat`.
3133
#' @param recursive logical. Should unlisting be applied to list components of result? See [unlist][base::unlist] for details.
3234
#' @param use.names logical. Should names be preserved? See [unlist][base::unlist] for details.
35+
#' @param fill logical. TRUE by default. Should we combine data.frames with different names in the `to_df`?
3336
#' @param data data.frame/list/vector which we want to alter
3437
#' @return list for `to_list` and vector for `to_vec`
3538
#' @export
@@ -58,6 +61,9 @@ SPECIAL_FUNCTIONS = expression(
5861
#' # gives only locally increasing values
5962
#' to_vec(for(`i, j` in lag_list(rand_sequence)) if(j>i) j)
6063
#'
64+
#' # to_df
65+
#' to_df(for(`name, x` in mark(mtcars)) list(mean = mean(x), sd = sd(x), var = name))
66+
#'
6167
#' # 'alter' examples
6268
#' data(iris)
6369
#' # scale numeric variables
@@ -248,6 +254,49 @@ alter = function(expr, data = NULL){
248254
}
249255

250256

257+
#' @rdname to_list
258+
#' @export
259+
to_df = function(expr, fill = TRUE){
260+
res = eval.parent(
261+
substitute(
262+
comprehenr::to_list(expr)
263+
)
264+
)
265+
for(i in seq_along(res)){
266+
if(!is.null(res[[i]]) && !is.data.frame(res[[i]])){
267+
res[[i]] = as.data.frame(as.list(res[[i]]))
268+
}
269+
}
270+
#
271+
if(fill){
272+
all_names = unique(unlist(lapply(res, names), use.names = FALSE))
273+
for(i in seq_along(res)){
274+
new_names = setdiff(all_names, names(res[[i]]))
275+
if(length(new_names)>0){
276+
res[[i]][,new_names] = NA
277+
}
278+
}
279+
}
280+
281+
do.call(rbind, res)
282+
}
283+
284+
# @rdname to_list
285+
# @export
286+
# to_dfr = to_df
287+
288+
# @rdname to_list
289+
# @export
290+
# to_dfc = function(expr = NULL){
291+
# res = eval.parent(
292+
# substitute(
293+
# comprehenr::to_list(expr)
294+
# )
295+
# )
296+
# as.data.frame(res)
297+
# }
298+
299+
251300
#' @rdname to_list
252301
#' @export
253302
exclude = function(){

inst/tinytest/test_to_list.R

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,32 @@ mtcars2= alter(for(`i,j` in lag_list(mtcars)) if(length(unique(i))==2) exclude()
217217
res_mtcars = mtcars
218218
res_mtcars[, c("am", "vs")] = NULL
219219
expect_equal(mtcars2, res_mtcars)
220+
221+
context("to_df/to_dfc")
222+
223+
data("mtcars")
224+
225+
expect_identical(
226+
to_df(for(each in list(1:2, 2:3, 3:4)) each),
227+
structure(list(X1L = c(1L, NA, NA), X2L = c(2L, 2L, NA), X3L = c(NA,
228+
3L, 3L), X4L = c(NA, NA, 4L)), row.names = c(NA, -3L), class = "data.frame")
229+
)
230+
231+
expect_error(
232+
to_df(for(each in list(1:2, 2:3, 3:4)) each, fill = FALSE),
233+
)
234+
235+
expect_equal(
236+
to_df(for(`.name, .x` in mark(mtcars)) list(mean = mean(.x), sd = sd(.x), var = .name)),
237+
data.frame(mean = colMeans(mtcars), sd = sapply(mtcars, sd), var = names(mtcars), row.names = seq_along(mtcars))
238+
)
239+
240+
241+
expect_identical(
242+
to_df(for(`.index, .x` in enumerate(mtcars)) list(mean = mean(.x), sd = sd(.x), item_id = .index)),
243+
data.frame(mean = colMeans(mtcars), sd = sapply(mtcars, sd), item_id = seq_along(mtcars), row.names = seq_along(mtcars))
244+
)
245+
246+
247+
248+

man/to_list.Rd

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)