R: Multidimensional array index assignment - r

Consider the following array assignments:
temp=array(list(),2)
temp[[2]][[2]]=c("a","b")
temp[[1]][[2]]="c"
This produces the following result:
temp
[[1]]
[1] NA "c"
[[2]]
[[2]][[1]]
NULL
[[2]][[2]]
[1] "a" "b"
Instead, I want the result to be:
temp
[[1]]
[[1]][[1]]
NULL
[[1]][[2]]
[1] "c"
[[2]]
[[2]][[1]]
NULL
[[2]][[2]]
[1] "a" "b"
How do I make the assignment so that the former is produced rather than the latter?

You can initialize the list(s) with replicate instead of array. Lists and arrays behave differently
x <- replicate(2, list())
x[[1]][[2]] <- "c"
x[[2]][[2]] <- c("a", "b")
x
Note:
is.array(x)
# [1] FALSE
sapply(x, is.array)
# [1] FALSE FALSE

Related

Processing nested lists in nested for loop

I have 2 variables, and I need to create all combinations using these 2 variables. I have been able to achieve this using R combn function, and finally store the combinations within a nested list. Now I need to run some calculation for each combination and store the combined output together. I am trying to store the output in a list but for some reason the output list is not being generated the correct way. Below is an example code:
''''
input_variables <- c("a","b")
output_sublist <- list()
output_biglist <- list()
input_combination_list <- list()
for (i in 1:length(input_variables)) {
input_combination_list[[i]] <- combn(input_variables, i, simplify = FALSE)
for(j in 1:length(input_combination_list[[i]])) {
input_combination_list[[i]][[j]]
output_sublist[[j]] <- input_combination_list[[i]][[j]]
}
output_biglist[[i]] <- output_sublist
}''''
The output that I get is:
[[1]]
[[1]][[1]]
[1] "a"
[[1]][[2]]
[1] "b"
[[2]]
[[2]][[1]]
[1] "a" "b"
[[2]][[2]]
[1] "b"
What I would like to have is:
[[1]]
[[1]][[1]]
[1] "a"
[[1]][[2]]
[1] "b"
[[2]]
[[2]][[1]]
[1] "a" "b"
I am not sure why there is an extra "b" in the end!! Any help would be greatly appreciated. Thanks a lot in advance.
output_sublist for i = 1 is
#[[1]]
#[1] "a"
#[[2]]
#[1] "b"
For i = 2, since we don't clear output_sublist it replaces only the first value and second value remains as it is.
#[[1]]
#[1] "a" "b"
#[[2]]
#[1] "b"
You need to clear output_sublist after each iteration of i.
for (i in 1:length(input_variables)) {
output_sublist <- list() #Added a line here to clear output_sublist
input_combination_list[[i]] <- combn(input_variables, i, simplify = FALSE)
for(j in 1:length(input_combination_list[[i]])) {
input_combination_list[[i]][[j]]
output_sublist[[j]] <- input_combination_list[[i]][[j]]
}
output_biglist[[i]] <- output_sublist
}
output_biglist
#[[1]]
#[[1]][[1]]
#[1] "a"
#[[1]][[2]]
#[1] "b"
#[[2]]
#[[2]][[1]]
#[1] "a" "b"
However, as mentioned in the comments we can do this with lapply as well
lapply(seq_along(input_variables), function(x)
combn(input_variables, x, simplify = FALSE))
#[[1]]
#[[1]][[1]]
#[1] "a"
#[[1]][[2]]
#[1] "b"
#[[2]]
#[[2]][[1]]
#[1] "a" "b"

How to perform a vectorised operation with a self-defined function, adding the results to a list?

library(tidyverse)
ridiculous_function <- function(a, b){
moo <- a
baz <- b
list(moo, baz)
}
test <- ridiculous_function("apple", "A")
> test
[[1]]
[1] "apple"
[[2]]
[1] "A"
This code produces a list of elements of a and b, however what I would like is to run the function over two vectors in parallel, and then put all of the results in the same list.
For example, with these two vectors:
fruits10 <- fruit[1:10]
letters10 <- LETTERS[1:10]
I would want to create a list which produces elements of character vectors for "apple", "A", "apricot", "B", "avocado", "C".. and so on. My real scenario is a lot more complex so I need a solution which works with the confines of my function.
Expected output:
> test
[[1]]
[1] "apple"
[[2]]
[1] "A"
[[3]]
[1] "apricot"
[[4]]
[1] "B"
[[5]]
[1] "avocado"
[[6]]
[1] "C"
....
[[19]]
[1] "blueberry"
[[20]]
[1] "T"
How about:
fruits10 <- fruit[1:10]
letters10 <- LETTERS[1:10]
ridiculous_function <- function(a, b){
moo <- a
baz <- b
list(moo, baz)
}
library(tidyverse)
flatten(map2(fruits10, letters10, ridiculous_function))
which gives you
[1]]
[1] "apple"
[[2]]
[1] "A"
[[3]]
[1] "apricot"
[[4]]
[1] "B"
[[5]]
[1] "avocado"
[[6]]
[1] "C"
[[7]]
[1] "banana"
[[8]]
[1] "D"
etc...
Here are a few different ways of doing this:
library(tidyverse)
fruits10 <- fruit[1:10]
letters10 <- LETTERS[1:10]
ridiculous_function <- function(a, b){
moo <- a
baz <- b
list(moo, baz)
}
# using mapply, base R for writing packages
mapply(ridiculous_function, fruits10, letters10) %>%
split(rep(1:ncol(.), each = nrow(.)))
# using map2, takes two args
map2(fruits10, letters10, ridiculous_function)
# using pmap, can take as many args as you want
list(a = fruits10,
b = letters10) %>%
pmap(ridiculous_function)
You ask for results in a flat list format, so you can pop a flatten at the end
of each of these, but usually you would want to retain the list structure.

R: how to apply to a list a function that joins all subelements except the first one

I am struggling with manipulating lists; now I want to join all subelements in an element EXCEPT THE FIRST ONE, in one operation if possible.
For example, 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] "B;C;D;E;F"
[[2]] [1] "B;C"
[[3]] [1] "B;C;D"
[[4]] [1] "B;C;D"
[[5]] [1] "B;C;D;E"
So I need a function to apply in this way:
list2 <- lapply(list1,
function(x) {
#something here
})
It would be awesome if the function could be easily modified to leave out a different subelement (not just the first one, but the 3rd, or the last, or 2nd to last...).
Many thanks!
Lets make a reproducible example:
> L = list(LETTERS[1:6], LETTERS[1:3],LETTERS[1:4],LETTERS[1:4],LETTERS[1:5])
> L
[[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"
Then you drop the first element and paste everything else together with a semicolon:
> lapply(L, function(x){paste(x[-1],collapse=";")})
[[1]]
[1] "B;C;D;E;F"
[[2]]
[1] "B;C"
[[3]]
[1] "B;C;D"
[[4]]
[1] "B;C;D"
[[5]]
[1] "B;C;D;E"
You get an empty string (no semicolons) if there's only one element in the list element to start with.
Read up about R's vector indexing to do selection of other elements of the x vector in the function.
[ is actually a function. You can try the below.
list1 <- list(
c("A", "B", "C"),
c("D", "E", "F", "G")
)
# for leaving out the first element
lapply(list1, `[`, -1)
# for leaving out the last element
lapply(list1, function(a) a[-length(a)])
# for leaving various elements
Map(`[`, list1, -c(1, 2))

R doubling list length when subsetting

I am currently trying to subset a list in R from a dataframe. My current attempt looks like:
list.level <- unique(buckets$group)
bucket.group <- vector("list",length(list.level))
for(i in list.level){
bucket.group[[i]] <- subset(buckets$group,buckets$group == i)
}
However, instead of filling the list it seems to create a duplicate list of the same amount of rows, returning:
[[1]]
NULL
[[2]]
NULL
...
NULL
[[22]]
NULL
[[23]]
NULL
$A
[1] "A"
$C
[1] "C" "C" "C"
$D
[1] "D" "D" "D"
...
$AJ
[1] "AJ" "AJ" "AJ" "AJ" "AJ"
$AK
[1] "AK" "AK"
A should be filling into 1, C into 2, etc. etc. How do I get these to fill in the original rows rather than creating extra rows at the bottom of the list?
Here is what is going on. Suppose your buckets$group is c("a","a","b","b").
list.level <- unique(buckets$group)
Now list.level is c("a","b")
bucket.group <- vector("list",length(list.level))
Since length(list.level) is 2, now your bucket.group is a list of 2 NULL elements, their names are 1 and 2.
for(i in list.level){
Recalling the value of list.level, it is the same as for i in c("a","b").
bucket.group[[i]] <- subset(buckets$group,buckets$group == i)
Since i loops over "a" and "b", you now fill bucket.group[["a"]] and bucket.group[["b"]], while bucket.group[[1]] and bucket.group[[2]] remain intact.
To fix this, you should write instead
list.level <- unique(buckets$group) # ok, this was correct
bucket.group <- list() # just empty list
for(i in 1:length(list.level)){
bucket.group[[i]] <- buckets$group[buckets$group == list.level[[i]] ]
}
I think the issue is with your for statement.
Your code is like this:
list.level<-letters[1:10]
> for(i in list.level) print(i)
[1] "a"
[1] "b"
[1] "c"
[1] "d"
[1] "e"
[1] "f"
[1] "g"
[1] "h"
[1] "i"
[1] "j"
It assigns each element in list.level to i, so i is a letter. When you do
bucket.group[[i]] <- subset(buckets$group,buckets$group == i)
in the first iteration, i is a letter. So it looks for a list element called bucket.group[["a"]] and does not find it, so it creates it and stores the data there. If instead you use seq_along
for(i in seq_along(list.level)) print(i)
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
now i will alway be a number and the code will do what you want.
So use seq_along instead.
this should work:
list.level <- unique(buckets$group)
bucket.group <- vector("list",length(list.level))
for(i in 1:length(list.level)){
bucket.group[[i]] <- subset(buckets$group,buckets$group == list.level[i])
}

How to flatten a list in an igraph vertex attribute

After several operations on an igraph object (g), I have ended up with the "id" attribute becoming full of nested lists.
It looks like this:
head(V(g)$id)
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] "http://www.parliament.uk/"
[[2]]
[[2]][[1]]
[[2]][[1]][[1]]
[1] "http://www.businesslink.gov.uk/"
[[3]]
[[3]][[1]]
[[3]][[1]][[1]]
[1] "http://www.number10.gov.uk/"
... and so forth.
I need to 'unnest' this list so it becomes:
head(V(g)$id)
[1] "http://www.parliament.uk/" "http://www.businesslink.gov.uk/"
[3] "http://www.number10.gov.uk/" "http://www.ombudsman.org.uk/"
[5] "http://www.hm-treasury.gov.uk/" "http://data.gov.uk/"
The nested list is causing problems when igraph exports the object to a graphml file. It results in the "id" being assigned default labels (e.g. n0, n1, n2...).
I have tried several other questions, particularly this one. However, I cannot get it to work. It is really frustrating!
Are you just looking for unlist, perhaps?
L <- list(list(list("A")), list(list("B")))
L
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] "A"
#
#
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [1] "B"
#
#
#
unlist(L)
# [1] "A" "B"

Resources