I'd trying to figure out how to transform a named list where the values are also list in a named list where the value is the result of a concatenation of the values within a vector.
I do not know if I explain correctly or easily, so follow the example.
x <- list(A = c("e", "f", "g"), B = c("a", "b", "c"), C = c("m", "l", "w"))
#$A
#[1] "e" "f" "g"
#$B
#[1] "a" "b" "c"
#$C
#[1] "m" "l" "w"
named_list_concat <- function(data){ ... }
named_list_concat(x)
#$A
#[1] "efg"
#$B
#[1] "abc"
#$C
#[1] "mlw"
One base possibility:
lapply(x, function(x) paste(x, collapse = ""))
$A
[1] "efg"
$B
[1] "abc"
$C
[1] "mlw"
Or the same thing in a shortened form:
lapply(x, paste, collapse = "")
Related
Using base R, I'd like to use the mapply function on a nested list. For example, in the code below, I'm trying to remove the letter "a" from each element of a nested list. I'd like to replace the last two lines with just a single line of code.
mylist <- list(
list(c("a", "b", "c"), c("d", "e", "f")),
list(c("a", "v", "w"), c("x", "y"), c("c", "b", "a"))
)
mylist
not_a <- lapply(mylist, lapply, `!=`, "a")
not_a
mylist[[1]] <- mapply(`[`, mylist[[1]], not_a[[1]], SIMPLIFY = FALSE)
mylist[[2]] <- mapply(`[`, mylist[[2]], not_a[[2]], SIMPLIFY = FALSE)
One option could be:
rapply(mylist, how = "replace", function(x) x[x != "a"])
[[1]]
[[1]][[1]]
[1] "b" "c"
[[1]][[2]]
[1] "d" "e" "f"
[[2]]
[[2]][[1]]
[1] "v" "w"
[[2]][[2]]
[1] "x" "y"
[[2]][[3]]
[1] "c" "b"
Or using map2
library(purrr)
map2(mylist, not_a, ~ map2(.x, .y, `[`))
Or using map_depth (if the OP is interested only in the final outcome)
map_depth(mylist, 2, ~ .x[.x != 'a'])
#[[1]]
#[[1]][[1]]
#[1] "b" "c"
#[[1]][[2]]
#[1] "d" "e" "f"
#[[2]]
#[[2]][[1]]
#[1] "v" "w"
#[[2]][[2]]
#[1] "x" "y"
#[[2]][[3]]
#[1] "c" "b"
Or more compactly
map_depth(mylist, 2, setdiff, 'a')
A double loop Map/mapply will do what the question asks for.
Map(function(i) mapply(`[`, mylist[[i]], not_a[[i]], SIMPLIFY = FALSE), seq_along(mylist))
Simpler:
Map(function(x, y) Map(`[`, x, y), mylist, not_a)
Suppose that I have a vector of length n and I need to generate all possible combinations and their sums. For example:
If n=3, we have:
myVec <- c("a", "b", "c")
Output =
"a"
"b"
"c"
"a+b"
"a+c"
"b+c"
"a+b+c"
Note that we consider that a+b = b+a, so only need to keep one.
Another example if n=4,
myVec <- c("a", "b", "c", "d")
Output:
"a"
"b"
"c"
"d"
"a+b"
"a+c"
"a+d"
"b+c"
"b+d"
"c+d"
"a+b+c"
"a+c+d"
"b+c+d"
"a+b+c+d"
We can use sapply with varying length in combn and use paste as function to apply.
sapply(seq_along(myVec), function(n) combn(myVec, n, paste, collapse = "+"))
#[[1]]
#[1] "a" "b" "c"
#[[2]]
#[1] "a+b" "a+c" "b+c"
#[[3]]
#[1] "a+b+c"
myVec <- c("a", "b", "c", "d")
sapply(seq_along(myVec), function(n) combn(myVec, n, paste, collapse = "+"))
#[[1]]
#[1] "a" "b" "c" "d"
#[[2]]
#[1] "a+b" "a+c" "a+d" "b+c" "b+d" "c+d"
#[[3]]
#[1] "a+b+c" "a+b+d" "a+c+d" "b+c+d"
#[[4]]
#[1] "a+b+c+d"
We can unlist if we need output as single vector.
I am trying to use combn to divide a group of n = 20 different units into 3 groups of unequal size -- 4, 6 and 10. Then I am trying to validate for values that must be together within a group -- if one element from the pair exists in the group then the other should also be in the group. If one is not in the group then neither should be in the group. In this fashion, I'd like to evaluate the groups in order to find all possible valid solutions where the rules are true.
x <- letters[1:20]
same_group <- list(
c("a", "c"),
c("d", "f"),
c("b", "k", "r")
)
combinations_list <- combn(x, 4, simplify = F)
validate_combinations <- function(x) all(c("a", "c") %in% x) | !any(c("a", "c") %in% x)
valid_combinations <- keep(combinations_list, validate_combinations)
In this way I'd like to combine -> reduce each group until I have a list of all valid combinations. I'm not sure how to combine combinations_list, validate_combinations, and the same_group to check all same_group "rules" against the combinations in the table. The furthest I can get is to check against one combination c("a", "c"), which when run against keep(combinations_list, validate_combinations) is indeed giving me the output I want.
I think once I can do this, I can then use the unpicked values in another combn function for the group of 6 and the group of 10.
We can change the function to accept variable group
validate_combinations <- function(x, group) all(group %in% x) | !any(group %in% x)
then for each group subset the combinations_list which satisfy validate_combinations
lapply(same_group, function(x) combinations_list[
sapply(combinations_list, function(y) validate_combinations(y, x))])
#[[1]]
#[[1]][[1]]
#[1] "a" "b" "c" "d"
#[[1]][[2]]
#[1] "a" "b" "c" "e"
#[[1]][[3]]
#[1] "a" "b" "c" "f"
#[[1]][[4]]
#[1] "a" "b" "c" "g"
#[[1]][[5]]
#[1] "a" "b" "c" "h"
#[[1]][[6]]
#[1] "a" "b" "c" "i"
#[[1]][[7]]
#[1] "a" "b" "c" "j"
#[[1]][[8]]
#[1] "a" "b" "c" "k"
#......
I need to create a list from rows of a dataframe in the following format:
df <- data.frame(y1 = c("a", "d"), y2 = c("b", "e"), y3 = c("c", "f"))
df$y1 <- as.character(df$y1)
df$y2 <- as.character(df$y2)
df$y3 <- as.character(df$y3)
x <- list(
list(y1 = df$y1[1],
y2 = df$y2[1],
y3 = df$y3[1]),
list(y1 = df$y1[2],
y2 = df$y2[2],
y3 = df$y3[2])
)
> x
[[1]]
[[1]]$`y1`
[1] "a"
[[1]]$y2
[1] "b"
[[1]]$y3
[1] "c"
[[2]]
[[2]]$`y1`
[1] "d"
[[2]]$y2
[1] "e"
[[2]]$y3
[1] "f"
This is an example when there are two rows in the dataframe. How can I achieve this when the number of rows in the dataframe is variable? So for every row in the dataframe, there should be a list.
We may also use apply by going over the rows and applying as.list to each:
apply(df, 1, as.list)
[[1]]
[[1]]$y1
[1] "a"
[[1]]$y2
[1] "b"
[[1]]$y3
[1] "c"
[[2]]
[[2]]$y1
[1] "d"
[[2]]$y2
[1] "e"
[[2]]$y3
[1] "f"
We first split every row of the dataframe and then for every row we convert each element into separate list element using as.list
lapply(split(df, 1:nrow(df)), as.list)
#$`1`
#$`1`$y1
#[1] "a"
#$`1`$y2
#[1] "b"
#$`1`$y3
#[1] "c"
#$`2`
#$`2`$y1
#[1] "d"
#$`2`$y2
#[1] "e"
#$`2`$y3
#[1] "f"
We can use transpose from purrr
library(purrr)
transpose(df)
#[1]]
#[[1]]$y1
#[1] "a"
#[[1]]$y2
#[1] "b"
#[[1]]$y3
#[1] "c"
#[[2]]
#[[2]]$y1
#[1] "d"
#[[2]]$y2
#[1] "e"
#[[2]]$y3
#[1] "f"
I have a list of vectors
list_of_vectors <- list(c("a", "b", "c"), c("a", "c", "b"), c("b", "c", "a"), c("b", "b", "c"), c("c", "c", "b"), c("b", "c", "b"), c("b", "b", "c", "d"), NULL)
For this list I would like to know which vectors are unique in terms of their elements. That is, I would like the following output
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "b" "b" "c"
[[3]]
[1] "c" "c" "b"
[[4]]
[1] "b" "b" "c" "d"
[[5]]
[1] NULL
Is there a function in R for performing this check? Or do I need do a lot of workarounds by writing functions?
My current not so elegant solution:
# Function for turning vectors into strings ordered by alphabet
stringer <- function(vector) {
if(is.null(vector)) {
return(NULL)
} else {
vector_ordered <- vector[order(vector)]
vector_string <- paste(vector_ordered, collapse = "")
return(vector_string)
}
}
# Identifying unique strings
vector_strings_unique <- unique(lapply(list_of_vectors, function(vector)
stringer(vector)))
vector_strings_unique
[[1]]
[1] "abc"
[[2]]
[1] "bbc"
[[3]]
[1] "bcc"
[[4]]
[1] "bbcd"
[[5]]
NULL
# Function for splitting the strings back into vectors
splitter <- function(string) {
if(is.null(string)) {
return(NULL)
} else {
vector <- unlist(strsplit(string, split = ""))
return(vector)
}
}
# Applying function
lapply(vector_strings_unique, function(string) splitter(string))
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "b" "b" "c"
[[3]]
[1] "c" "c" "b"
[[4]]
[1] "b" "b" "c" "d"
[[5]]
[1] NULL
It does the trick and could be rewritten as a single function, but there must be a more elegant solution.
We can sort the list elements, apply duplicated to get a logical index of unique elements and subset the list based on that
list_of_vectors[!duplicated(lapply(list_of_vectors, sort))]
#[[1]]
#[1] "a" "b" "c"
#[[2]]
#[1] "b" "b" "c"
#[[3]]
#[1] "c" "c" "b"
#[[4]]
#[1] "b" "b" "c" "d"
#[[5]]
#NULL