Skip to content

Commit 1ea4909

Browse files
committed
'modify'-> 'alter'
1 parent 81402fa commit 1ea4909

File tree

10 files changed

+263
-31
lines changed

10 files changed

+263
-31
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.0
4+
Version: 0.6.5
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
export(alter)
34
export(enumerate)
45
export(lag_list)
56
export(mark)
6-
export(modify)
77
export(numerate)
88
export(to_list)
99
export(to_vec)

NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
0.6.5 (09.04.2019)
22
================
3-
* add for lists/data.frames modification
3+
* add 'alter' function for conditional lists/data.frames modification
44

55
0.6.0 (18.03.2019)
66
================

R/to_list.R

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
#' List comprehensions for R
22
#'
3-
#' \code{to_list} converts usual R loops expressions to list producers.
3+
#' \itemize{\item{\code{to_list}}{ converts usual R loops expressions to list producers.
44
#' Expression should be started with \code{for} , \code{while} or
55
#' \code{repeat}. You can iterate over multiple lists if you provide several
6-
#' loop variables in backticks. See examples.
6+
#' loop variables in backticks. See examples.}
7+
#' \item{\code{to_vec}}{ is the same as \code{to_list} but return vector. See examples.}
8+
#' \item{\code{alter}}{ return the same type as its argument but with modified
9+
#' elements. It is useful for altering existing data.frames or lists. See
10+
#' examples.}
11+
#' }
712
#' @param expr expression which starts with \code{for} , \code{while} or \code{repeat}.
813
#' @param recursive logical. Should unlisting be applied to list components of result? See \link[base]{unlist} for details.
914
#' @param use.names logical. Should names be preserved? See \link[base]{unlist} for details.
15+
#' @param data data.frame/list/vector which we want to alter
1016
#' @return list for \code{to_list} and vector for \code{to_vec}
1117
#' @export
1218
#'
@@ -33,6 +39,31 @@
3339
#' rand_sequence = runif(20)
3440
#' # gives only locally increasing values
3541
#' to_vec(for(`i, j` in lag_list(rand_sequence)) if(j>i) j)
42+
#'
43+
#' # 'alter' examples
44+
#' data(iris)
45+
#' # scale numeric variables
46+
#' res = alter(for(i in iris) if(is.numeric(i)) scale(i))
47+
#' str(res)
48+
#'
49+
#' # convert factors to characters
50+
#' res = alter(for(i in iris) if(is.factor(i)) as.character(i))
51+
#' str(res)
52+
#'
53+
#' # 'data' argument example
54+
#' # specify which columns to map with a numeric vector of positions:
55+
#' res = alter(
56+
#' for(`i, value` in numerate(mtcars)) if(i %in% c(1, 4, 5)) as.character(value),
57+
#' data = mtcars
58+
#' )
59+
#' str(res)
60+
#'
61+
#' # or with a vector of names:
62+
#' res = alter(
63+
#' for(`name, value` in mark(mtcars)) if(name %in% c("cyl", "am")) as.character(value),
64+
#' data = mtcars
65+
#' )
66+
#' str(res)
3667
to_list = function(expr){
3768
expr = substitute(expr)
3869
if(!is_loop(expr)) {
@@ -41,7 +72,7 @@ to_list = function(expr){
4172

4273
expr = expand_loop_variables(expr)
4374
expr = add_assignment_to_final_loops(expr)
44-
on.exit(suppressWarnings(rm(list = c(".___res", ".___counter", ".__curr"), envir = parent.frame())))
75+
on.exit(suppressWarnings(rm(list = c(".___res", ".___counter", ".___curr"), envir = parent.frame())))
4576
eval.parent(quote(.___res <- list()))
4677
eval.parent(quote(.___counter <- 0)) # initial list length
4778
eval.parent(expr)
@@ -131,20 +162,20 @@ add_assignment_to_loop = function(expr, result_exists = FALSE){
131162
last_item = length(expr)
132163
if(result_exists){
133164
expr[[last_item]] = bquote({
134-
.__curr = {.(expr[[last_item]])}
165+
.___curr = {.(expr[[last_item]])}
135166
.___counter = .___counter + 1
136-
if(!is.null(.__curr)){
137-
.___res[[.___counter]] = .__curr
167+
if(!is.null(.___curr)){
168+
.___res[[.___counter]] = .___curr
138169
}
139170

140171
})
141172
} else {
142173
expr[[last_item]] = bquote({
143174

144-
.__curr = {.(expr[[last_item]])}
145-
if(!is.null(.__curr)){
175+
.___curr = {.(expr[[last_item]])}
176+
if(!is.null(.___curr)){
146177
.___counter = .___counter + 1
147-
.___res[[.___counter]] = .__curr
178+
.___res[[.___counter]] = .___curr
148179
}
149180

150181
})
@@ -154,12 +185,12 @@ add_assignment_to_loop = function(expr, result_exists = FALSE){
154185

155186
#' @rdname to_list
156187
#' @export
157-
modify = function(expr, data = NULL){
188+
alter = function(expr, data = NULL){
158189
expr = substitute(expr)
159190
if(!is_loop(expr)) {
160191
stop(paste("argument should be expression with 'for', 'while' or 'repeat' but we have: ", deparse(expr, width.cutoff = 500)[1]))
161192
}
162-
on.exit(suppressWarnings(rm(list = c(".___res", ".___counter", ".__curr"), envir = parent.frame())))
193+
on.exit(suppressWarnings(rm(list = c(".___res", ".___counter", ".___curr"), envir = parent.frame())))
163194
if(is.null(data)) data = expr[[3]]
164195
eval.parent(substitute(.___res <- data))
165196
expr = expand_loop_variables(expr)

README.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,23 @@ expressions use usual loops (`for`, `while` and `repeat`) and usual `if` as
1010
list producers. Syntax is very similar to Python. The difference is that
1111
returned value should be at the end of the loop body.
1212

13-
```R
14-
# rather useless statement - squares of even numbers
15-
to_list(for(i in 1:10) if(i %% 2==0) i*i)
13+
There are three main functions:
1614

17-
# Pythagorean triples
18-
to_list(for (x in 1:20) for (y in x:20) for (z in y:20) if (x^2 + y^2 == z^2) c(x, y, z))
15+
- `to_list` converts usual R loops expressions to list producers. Expression should be started with `for`, `while` or `repeat`. You can iterate over multiple lists if you provide several loop variables in backticks. See examples.
16+
- `to_vec` is the same as `to_list` but return vector. See examples.
17+
- `alter` return the same type as its argument but with modified elements. It is useful for altering existing data.frames or lists. See examples.
1918

19+
Rather unpractical example - squares of even numbers:
20+
```R
21+
library(comprehenr)
22+
to_vec(for(i in 1:10) if(i %% 2==0) i*i)
23+
```
24+
Pythagorean triples:
25+
```R
26+
to_list(for (x in 1:20) for (y in x:20) for (z in y:20) if (x^2 + y^2 == z^2) c(x, y, z))
27+
```
28+
More examples:
29+
```R
2030
colours = c("red", "green", "yellow", "blue")
2131
things = c("house", "car", "tree")
2232
to_vec(for(x in colours) for(y in things) paste(x, y))
@@ -36,3 +46,30 @@ rand_sequence = runif(20)
3646
to_vec(for(`i, j` in lag_list(rand_sequence)) if(j>i) j)
3747

3848
```
49+
50+
`alter` examples:
51+
```R
52+
data(iris)
53+
# scale numeric variables
54+
res = alter(for(i in iris) if(is.numeric(i)) scale(i))
55+
str(res)
56+
57+
# convert factors to characters
58+
res = alter(for(i in iris) if(is.factor(i)) as.character(i))
59+
str(res)
60+
61+
# 'data' argument example
62+
# specify which columns to map with a numeric vector of positions:
63+
res = alter(
64+
for(`i, value` in numerate(mtcars)) if(i %in% c(1, 4, 5)) as.character(value),
65+
data = mtcars
66+
)
67+
str(res)
68+
69+
# or with a vector of names:
70+
res = alter(
71+
for(`name, value` in mark(mtcars)) if(name %in% c("cyl", "am")) as.character(value),
72+
data = mtcars
73+
)
74+
str(res)
75+
```

man/to_list.Rd

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

tests/testthat/test_to_list.R

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ expect_equal(
3636
)
3737
expect_false(exists(".___res"))
3838
expect_false(exists(".___counter"))
39-
expect_false(exists(".__curr"))
39+
expect_false(exists(".___curr"))
4040

4141
expect_error(to_list(for(i in 1:10) i*brrrr))
4242
expect_false(exists(".___res"))
4343
expect_false(exists(".___counter"))
44-
expect_false(exists(".__curr"))
44+
expect_false(exists(".___curr"))
4545

4646

4747
expect_error(to_list(1))
4848
expect_false(exists(".___res"))
4949
expect_false(exists(".___counter"))
50-
expect_false(exists(".__curr"))
50+
expect_false(exists(".___curr"))
5151
a = 11
5252
expect_error(to_list(a + 2))
5353

@@ -119,20 +119,20 @@ true_res = paste(true_res[[2]], true_res[[1]])
119119
expect_identical(res, true_res)
120120

121121

122-
context("modify")
122+
context("alter")
123123
data(iris)
124-
iris2 = modify(for(i in iris) if(is.numeric(i)) scale(i))
124+
iris2 = alter(for(i in iris) if(is.numeric(i)) scale(i))
125125
res_iris = iris
126126
res_iris[,-5] = lapply(iris[,-5], scale)
127127
expect_equal(iris2, res_iris)
128128

129-
iris2 = modify(for(`name, value` in mark(iris)) if(grepl("Width", name)) scale(value), data = iris)
129+
iris2 = alter(for(`name, value` in mark(iris)) if(endsWith(name, "Width")) scale(value), data = iris)
130130

131131
res_iris = iris
132132
res_iris[,c("Sepal.Width", "Petal.Width")] = lapply(iris[,c("Sepal.Width", "Petal.Width")], scale)
133133
expect_equal(iris2, res_iris)
134134

135-
135+
expect_error(alter(1))
136136
# library(data.table)
137137
# dt_iris = as.data.table(iris)
138-
# dt_iris2 = modify(for(i in dt_iris) if(is.numeric(i)) scale(i))
138+
# dt_iris2 = alter(for(i in dt_iris) if(is.numeric(i)) scale(i))

vignettes/Introduction.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,28 @@ rand_sequence = runif(20)
3030
to_vec(for(`i, j` in lag_list(rand_sequence)) if(j>i) j)
3131

3232

33+
## ------------------------------------------------------------------------
34+
data(iris)
35+
# scale numeric variables
36+
res = alter(for(i in iris) if(is.numeric(i)) scale(i))
37+
str(res)
38+
39+
# convert factors to characters
40+
res = alter(for(i in iris) if(is.factor(i)) as.character(i))
41+
str(res)
42+
43+
# 'data' argument example
44+
# specify which columns to map with a numeric vector of positions:
45+
res = alter(
46+
for(`i, value` in numerate(mtcars)) if(i %in% c(1, 4, 5)) as.character(value),
47+
data = mtcars
48+
)
49+
str(res)
50+
51+
# or with a vector of names:
52+
res = alter(
53+
for(`name, value` in mark(mtcars)) if(name %in% c("cyl", "am")) as.character(value),
54+
data = mtcars
55+
)
56+
str(res)
57+

0 commit comments

Comments
 (0)