I have several vectors and lists, for example:
colors <- c("blue", "blue", "red", "green", "green")
shapes <- c("square", "square", "triangle", "triangle", "circle")
numbers <- c(22, 50, 50, 50, 13, 13)
list_of_dfs <- list(mtcars, mtcars, iris, iris, trees, trees, trees)
is_foo <- c(TRUE, FALSE, TRUE)
It is not a coincidence that except for is_foo, all other objects are of the same length after calling unique() on them.
I want to build a tibble such that I take the unique() of some (but not all) such that:
library(tibble)
my_tib <-
tibble(colors = unique(colors),
shapes = unique(shapes),
numbers = unique(numbers),
dfs = unique(list_of_dfs),
is_foo = is_foo)
My problem: I want to build my_tib in a more succinct way. Meaning, I don't want to call unique() on each column separately, but all at once for the columns that need to be unique'ed (in this case, all except for is_foo that goes as-is).
How can we do so if colors, shapes, numbers, list_of_dfs, and is_foo are given?
CodePudding user response:
You can build a list first and use purrr:modify_at to apply unique to only selected elements. purrr::modify_at also allows tidyselect syntax so you have better control over the elements you want to modify. However, I don't see the point here since it does not shorten your code or reduce the number of operations to perform.
library(tibble)
library(purrr)
as_tibble(modify_at(list(
colors = colors,
shapes = shapes,
numbers = numbers,
dfs = list_of_dfs,
is_foo = is_foo
), vars(!is_foo), unique))
Output
# A tibble: 3 x 5
colors shapes numbers dfs is_foo
<chr> <chr> <dbl> <list> <lgl>
1 blue square 22 <df [32 x 11]> TRUE
2 red triangle 50 <df [150 x 5]> FALSE
3 green circle 13 <df [31 x 3]> TRUE
Or maybe use mget to get the variables so that you do not have to list them all.
cols <- c("colors", "shapes", "numbers", "list_of_dfs", "is_foo")
as_tibble(modify_at(mget(cols), vars(!is_foo), unique))
Output
# A tibble: 3 x 5
colors shapes numbers list_of_dfs is_foo
<chr> <chr> <dbl> <list> <lgl>
1 blue square 22 <df [32 x 11]> TRUE
2 red triangle 50 <df [150 x 5]> FALSE
3 green circle 13 <df [31 x 3]> TRUE
CodePudding user response:
Making use of a helper function which makes use of tibble::lst you could do:
Note: At least for the general case multiple columns to add as is I failed to pass the columns as a simple list. Instead they have to be wrapped inside tibble::lst.
library(dplyr)
make_tibble <- function(..., add) {
args <- lapply(lst(...), unique)
tibble(!!!c(args, add))
}
make_tibble(colors, shapes, numbers, list_of_dfs, add = lst(is_foo, bar))
#> # A tibble: 3 × 6
#> colors shapes numbers list_of_dfs is_foo bar
#> <chr> <chr> <dbl> <list> <lgl> <int>
#> 1 blue square 22 <df [32 × 11]> TRUE 1
#> 2 red triangle 50 <df [150 × 5]> FALSE 2
#> 3 green circle 13 <df [31 × 3]> TRUE 3
