Combine list components to a vector - r

Suppose, I have a list:
l = list(c("a", "b", "c"), c("d", "e", "f"))
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "d" "e" "f"
I want to get a vector.
"ad" "be" "cf"
I can convert the list to a matrix, e.g.,sapply(l, c), and then concatenate columns, but, perhaps, there is an easier way.

We can use Reduce with paste0
Reduce(paste0, l)
[1] "ad" "be" "cf"
Or with do.call
do.call(paste0, l)
[1] "ad" "be" "cf"

Here is another option
> apply(list2DF(l), 1, paste0, collapse = "")
[1] "ad" "be" "cf"

Related

How to generate all permutations of lists of string?

I have character data like this
[[1]]
[1] "F" "S"
[[2]]
[1] "Y" "Q" "Q"
[[3]]
[1] "C" "T"
[[4]]
[1] "G" "M"
[[5]]
[1] "A" "M"
And I want to generate all permutations for each individual list (not mixed between lists) and combine them together into one big list.
For example, for the first and second lists, which are "F" "S" and "Y" "Q" "Q", I want to get the permutation lists as c("FS", "SF"), and c("YQQ", "QYQ", "QQY"), and then combine them into one.
Here's an approach with combinat::permn:
library(combinat)
lapply(data,function(x)unique(sapply(combinat::permn(x),paste,collapse = "")))
#[[1]]
#[1] "FS" "SF"
#
#[[2]]
#[1] "YQQ" "QYQ" "QQY"
#
#[[3]]
#[1] "CT" "TC"
#
#[[4]]
#[1] "GM" "MG"
#
#[[5]]
#[1] "AM" "MA"
Or together with unlist:
unlist(lapply(data,function(x)unique(sapply(combinat::permn(x),paste,collapse = ""))))
# [1] "FS" "SF" "YQQ" "QYQ" "QQY" "CT" "TC" "GM" "MG" "AM" "MA"
Data:
data <- list(c("F", "S"), c("Y", "Q", "Q"), c("C", "T"), c("G", "M"),
c("A", "M"))
It looks like your desired output is not exactly the same as this related post (Generating all distinct permutations of a list in R). But we can build on the answer there.
library(combinat)
# example data, based on your description
X <- list(c("F","S"), c("Y", "Q", "Q"))
result <- lapply(X, function(x1) {
unique(sapply(permn(x1), function(x2) paste(x2, collapse = "")))
})
print(result)
Output
[[1]]
[1] "FS" "SF"
[[2]]
[1] "YQQ" "QYQ" "QQY"
The first (outer) lapply iterates over each element of the list, which contains the individual letters (in a vector). With each iteration the permn takes the individual letters (eg "F" and "S"), and returns a list object with all possible permutations (e.g "F" "S" and "S" F"). To format the output as you described, the inner sapply takes each those permutations and collapses them into a single character value, filtered for unique values.
library(combinat)
final <- unlist(lapply(X , function(test_X) lapply(permn(test_X), function(x) paste(x,collapse='')) ))

Remove duplicates in a nested list

I have a large list of lists where I want to remove duplicated elements in each list. Example:
x <- list(c("A", "A", "B", "C"), c("O", "C", "A", "Z", "O"))
x
[[1]]
[1] "A" "A" "B" "C"
[[2]]
[1] "O" "C" "A" "Z" "O"
I want the result to be a list that looks like this, where duplicates within a list are removed, but the structure of the list remains.
[[1]]
[1] "A" "B" "C"
[[2]]
[1] "O" "C" "A" "Z"
My main strategy has been to use rapply (also tried lapply) to identify duplicates and remove them. I tried:
x[rapply(x, duplicated) == T]
but received the following error:
"Error: (list) object cannot be coerced to type 'logical'"
Does anyone know a way to solve this issue?
Thanks!
We can use lapply with unique
lapply(x, unique)
#[[1]]
#[1] "A" "B" "C"
#[[2]]
#[1] "O" "C" "A" "Z"
The issue with rapply, is that it recursively applies the duplicated and then returns a single vector instead of a list of logical vectors
rapply(x, duplicated)
#[1] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
Instead it can be
lapply(x, function(u) u[!duplicated(u)])
#[[1]]
#[1] "A" "B" "C"
#[[2]]
#[1] "O" "C" "A" "Z"

R - List manipulation element concatenation

Assume I have a list with 5 elements:
list <- list("A", "B", "C", "D", c("E", "F"))
I am trying to return this to a simple character vector using purrr with the need to combine list elements that have two strings into one, separated by a delimiter such as '-'. The output should look like this:
chr [1:5] "A" "B" "C" "D" "E-F"
I've tried a ton of approaches including paste, paste0, str_c and where I am getting hung up is it seems that map applies the function to each individual string of an element of a list and not the group of strings of an element (when there are more than one). The closes I've gotten is:
list2 <- unlist(map(list, str_flatten))
str(list2)
This returns:
chr [1:5] "A" "B" "C" "D" "EF"
where I need a hyphen between E and F:
chr [1:5] "A" "B" "C" "D" "E-F"
When I try to pass a function as a parenthetiinton to str_flatten(), such as str_flatten(list, collapse = "-"), it doesn't work. The big problem is I can't figure out what string to pass as an argument in str_flatten to group two strings of a given element of a list.
You almost had it. Try
library(purrr)
library(stringr)
unlist(map(lst, str_flatten, collapse = "-"))
#[1] "A" "B" "C" "D" "E-F"
You could also use map_chr
map_chr(lst, str_flatten, collapse = "-")
Without additional packages and with thanks to #G.Grothendieck you could do
sapply(lst, paste, collapse = "-")
data
lst <- list("A", "B", "C", "D", c("E", "F"))
We can also use map_chr and paste.
library(purrr)
lst <- list("A", "B", "C", "D", c("E", "F"))
map_chr(lst, ~paste(.x, collapse = "-"))
# [1] "A" "B" "C" "D" "E-F"

R: how to apply to a list a function that loops over the previous subelements

I guess this is better understood with an example, I feel this is really easy but I cannot get around it...
I have a list that looks like this:
[[1]] [1] "A" "B" "C" "D" "E" "F"
[[2]] [1] "A" "B" "C"
[[3]] [1] "A" "B" "C" "D"
[[4]] [1] "A" "B" "C" "D"
[[5]] [1] "A" "B" "C" "D" "E"
And I want to obtain this:
[[1]] [1] "A" "A;B" "A;B;C" "A;B;C;D" "A;B;C;D;E" "A;B;C;D;E;F"
[[2]] [1] "A" "A;B" "A;B;C"
[[3]] [1] "A" "A;B" "A;B;C" "A;B;C;D"
[[4]] [1] "A" "A;B" "A;B;C" "A;B;C;D"
[[5]] [1] "A" "A;B" "A;B;C" "A;B;C;D" "A;B;C;D;E"
So I need a function to apply in this way:
list2 <- lapply(list1,
function(x) {
#something here
})
We can loop through the list, get the sequence of the length of elements, loop through it with sapply, extract the list elements based on the index and paste
lapply(list1, function(x) sapply(seq(length(x)),
function(i) paste(x[seq_len(i)], collapse=",")))
#[[1]]
#[1] "A" "A,B" "A,B,C" "A,B,C,D" "A,B,C,D,E" "A,B,C,D,E,F"
#[[2]]
#[1] "A" "A,B" "A,B,C"
#[[3]]
#[1] "A" "A,B" "A,B,C" "A,B,C,D"
#[[4]]
#[1] "A" "A,B" "A,B,C" "A,B,C,D"
#[[5]]
#[1] "A" "A,B" "A,B,C" "A,B,C,D" "A,B,C,D,E"
Or another option is Reduce with accumulate = TRUE
lapply(list1, function(x) Reduce(function(...) paste(..., sep=","), x, accumulate = TRUE))
This can be written without an anonymous function call if the sep is not important
lapply(list1, Reduce, f = paste, accumulate = TRUE)
data
list1 <- lapply(c(6, 3, 4, 4, 5), function(i) LETTERS[1:i])

I try to append chars, but i always get a gap between them

I try to append chars, but i always get a gap between them.
Instead of: "ab" i get "a b" for example.
I tried: append and paste.
paste("a", "b")
[1] "a b"
paste("a", "b", sep="")
[1] "ab"
paste0("a", "b")
[1] "ab"
use collapse=""
paste(c("a", "b"), collapse="")
# [1] "ab"
or paste0:
paste0("a", "b")
# [1] "ab"
(which is short for paste("a", "b", sep=""))
Another option would be sprintf:
sprintf("%s%s", "a", "b")
# [1] "ab"

Resources