Using list as a key for list - r

Is it anyhow possible to use list as a key for a list? I'd like something as below to work:
lst <- list()
lst[[ list("a", 1:2) ]] <- list(name = "first item", id = 1)
## Error in lst[[list("a", 1:2)]] <- list(name = "first item", id = 1) :
## invalid subscript type 'list'
The idea is to create a lookup table with list keys. The simple solution is to use hashes as keys (e.g. fastdigest), but I am wondering if there is no any direct solution for this?
Example:
lst <- list()
lst[[ list(V1 = "a", V2 = 1:2, V3 = NULL) ]] <- list(name = "first item", id = 1)
lst[[ list(V1 = "a", V2 = 1:2, V3 = "lorem ipsum") ]] <- list(name = "second item", id = 2)
lst[[ list(V1 = "b", V2 = 3, V3 = "") ]] <- list(name = "third item", id = 3)
# calling it:
lst[[ list(V1 = "b", V2 = 3, V3 = "") ]]
## list(name = "third item", id = 3)
The basic problem with using hashes is that I would like also to be able to back-transform this data structure to "flat" list, e.g.
list(V1 = "a", V2 = 1:2, V3 = NULL, name = "first item", id = 1)
and with hashes, for doing this I would need to store the key-hash dictionary separately to be able to re-create them etc. It would also need defining my own, pretty complicated, classes and methods for accessing them. So I'm asking if there is no direct solution, i.e. using lists as keys?

Related

how to make two networks connected with selected members

I have a data like this
df<- structure(list(Core = c("Bestman", "Tetra"), member1 = c("Tera1",
"Brownie1"), member2 = c("Tera2", "Brownie2"), member3 = c("Tera3",
"Brownie3"), member4 = c("Tera4", "Brownie4"), member5 = c("Tera5",
"Brownie5"), member6 = c("", "Brownie6"), member7 = c("", "Brownie7"
)), class = "data.frame", row.names = c(NA, -2L))
I want to connect all the members to their Core. for example if you look at the first row, you can see there are 5 members , I want to connect them to their Core
The same for the second row
Then I connect both Core together
Here is what I have done
mydf <- crossprod(table(cbind(df[1], stack(df[-1]))[-3]))
graph_from_adjacency_matrix(mydf, diag = F, weighted = T, mode = "undirected") %>%
plot(edge.width = E(.)$weight)
If i understood correctly, what you want is:
library(igraph)
df<- data.frame(Core = c("Bestman", "Tetra"), member1 = c("Tera1",
"Brownie1"), member2 = c("Tera2", "Brownie2"), member3 = c("Tera3",
"Brownie3"), member4 = c("Tera4", "Brownie4"), member5 = c("Tera5",
"Brownie5"), member6 = c("", "Brownie6"), member7 = c("", "Brownie7"))
edges <- t(do.call(rbind, apply(
df, 1, function(x) cbind(x[1], x[x!=""][-1]))))
core_edges <- if(nrow(df)>1) combn(df$Core,2) else c()
g<-graph(c(edges,core_edges), directed=F )
plot(g , edge.width = E(g)$weight)
EDIT
To colorize and resize nodes:
V(g)$color <- apply(df, 1, \(x) names(V(g)) %in% x) |> apply(1,which)
V(g)$size <- 15
V(g)[df$Core]$size <- degree(g, V(g)[df$Core]) + 15
plot(g)

How to loop dataframe in R

I want to get data from IMF.However the API data is limited
Therefor I get the data by continent.
How to loop the dateframe? (The data can get from "Before loop part",load data from api)
The reference cannot work.https://stackoverflow.com/questions/25284539/loop-over-a-string-variable-in-r
Before the loop
library(imfr)
library(countrycode)
data(codelist)
country_set <- codelist
country_set<- country_set %>%
select(country.name.en , iso2c, iso3c, imf, continent, region) %>% filter(!is.na(imf) & !is.na(iso2c))
africa_iso2<- country_set$iso2c[country_set$continent=="Africa"]
asia_iso2<- country_set$iso2c[country_set$continent=="Asia"]
americas_iso2<- country_set$iso2c[country_set$continent=="Americas"]
europe_iso2<- country_set$iso2c[country_set$continent=="Europe"]
oceania_iso2<- country_set$iso2c[country_set$continent=="Oceania"]
loop part
continent <- c("africa", "asia", "americas","europe","oceania")
for(i in 1:length(continent)){
var <- paste0("gdp_nsa_xdc_", continent[i])
var1 <- paste0(continent[i],"_iso2")
[[var]]<- imf_data(database_id = "IFS" , indicator = c("NGDP_NSA_XDC"),country =[[var1]],start = 2010, end = 2022,return_raw = TRUE)
[[var]]<- [[var]]$CompactData$DataSet$Series
}
data sample is
list(CompactData = list(`#xmlns:xsi` = "http://www.w3.org/2001/XMLSchema-instance",
`#xmlns:xsd` = "http://www.w3.org/2001/XMLSchema", `#xsi:schemaLocation` = "http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message https://registry.sdmx.org/schemas/v2_0/SDMXMessage.xsd http://dataservices.imf.org/compact/IFS http://dataservices.imf.org/compact/IFS.xsd",
`#xmlns` = "http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message",
Header = list(ID = "18e0aeae-09ec-4dfe-ab72-60aa16aaea84",
Test = "false", Prepared = "2022-10-19T12:02:28", Sender = list(
`#id` = "1C0", Name = list(`#xml:lang` = "en", `#text` = "IMF"),
Contact = list(URI = "http://www.imf.org", Telephone = "+ 1 (202) 623-6220")),
Receiver = list(`#id` = "ZZZ"), DataSetID = "IFS"), DataSet = list(
`#xmlns` = "http://dataservices.imf.org/compact/IFS",
Series = list(`#FREQ` = "Q", `#REF_AREA` = "US", `#INDICATOR` = "NGDP_NSA_XDC",
`#UNIT_MULT` = "6", `#TIME_FORMAT` = "P3M", Obs = structure(list(
`#TIME_PERIOD` = c("2020-Q1", "2020-Q2", "2020-Q3",
"2020-Q4", "2021-Q1", "2021-Q2", "2021-Q3", "2021-Q4",
"2022-Q1", "2022-Q2"), `#OBS_VALUE` = c("5254152",
"4930197", "5349433", "5539370", "5444406", "5784816",
"5883177", "6203369", "6010733", "6352982")), class = "data.frame", row.names = c(NA,
10L))))))
I suggest you create a list first, to which you will assign the value you want your loop to create. The following code creates a named list, and then at the end of the loop, assigns the value of each iteration to that named list:
continent <-
sapply(c("africa", "asia", "americas","europe","oceania"),
c, simplify = FALSE, USE.NAMES = TRUE)
for(i in seq_len(length(continent))) {
var <- paste0("gdp_nsa_xdc_", continent[i])
var1 <- get(paste0(continent[i],"_iso2"))
var <- imf_data(database_id = "IFS" , indicator = c("NGDP_NSA_XDC"),
country = var1, start = 2010, end = 2022,
return_raw = TRUE)
continent[[i]] <- var$CompactData$DataSet$Series
}
I don't necessarily understand the double brackets around [[var]]. Let me know if my answer does not correspond to what you were looking for!
We could use assign to create objects in the global env
for(i in 1:length(continent)){
var <- paste0("gdp_nsa_xdc_", continent[i])
var1 <- paste0(continent[i],"_iso2")
assign(var, imf_data(database_id = "IFS" , indicator = c("NGDP_NSA_XDC"),country =[[var1]],start = 2010, end = 2022,
return_raw = TRUE))
assign(var, get(var)$CompactData$DataSet$Series)
}

In R--Change name of list of list of lists when lists have differing lengths

I've tried everything I can...I have a large list of lists. They are of varying depths, but they all have a variable name that I need to rename. I tried breaking apart the list into data frames, it just seems unpractical and doesn't even do what I want.
Here's a toy example:
list1 = list(changethis = c("1", "2"))
list2 = list(varname1 = c("1,2,3,4"), changethis = c("5,6,7,8"), varname2 = c("9, 10, 11"))
list3 = list(varname3 = list(varname4 = c("first", "second", "third", list(changethis = c("15, 16, 19"), varname5 = "cat", "dog", "fish"))))
list4 = list(varname6 = list(varname7 = list2, varname8 = list2))
list5a = list(varname13 = c("hat", "key"), changethis = c("5"))
list5 = list(varname9 = list(varname10 = list5a, varname11 = list5a))
list6 = list(varname12 = list5)
list7 = list(first = list1)
listbig = list(sublist1 = list3, sublist2 = list4, sublist3 = list5, sublist4= list6, sublist5=list7, sublist6 = list5a)
Here's a toy code that produces what I want it to look like. The 'changethis' var is renamed to 'change'
sollist1 = list(changed= c("1", "2"))
sollist2 = list(varname1 = c("1,2,3,4"), changed = c("5,6,7,8"), varname2 = c("9, 10, 11"))
sollist3 = list(varname3 = list(varname4 = c("first", "second", "third", list(changed = c("15, 16, 19"), varname5 = "cat", "dog", "fish"))))
sollist4 = list(varname6 = list(varname7 = sollist2, varname8 = sollist2))
sollist5a = list(varname13 = c("hat", "key"), changed = c("5"))
sollist5 = list(varname9 = list(varname10 = sollist7, varname11 = sollist5a))
sollist6 = list(varname12 = sollist5)
sollist7 = list(first = sollist1)
solution_list = list(sublist1 = sollist3, sublist2 = sollist4, sublist3 = sollist5, sublist4= sollist6, sublist5=sollist7, sublist6=sollist7)
Here is one of my many attempts to do this. I extracted sublist1 from the big list and tried to just change the name for it, but nothing gets changed.
extr_sublist1 <- listbig[1]
names(extr_sublist1[[1]][[1]][[1]][4]) <- "changed" #does not do it...
Another failed attempt:
In this I extract a differently hierarchial sublist and create a Var name which I hope to loop over so I can change the name of the 'changethis' var. Also does not work.
extr_sublist4 <- listbig[4]
numvars <- length(extr_sublist4[[1]][[1]][[1]])
for (i in 1: numvars){
varname<-paste("Var",numvar, sep = "")
paste('Var',[i]) <- extr_sublist4[[1]][[1]][[1]][[1]][2]
namespaste('Var',[i])[paste('Var',[i]) == 'changethis'] <- 'changed'
}
I'm sure there's a simple and elegant solution to this...but have no idea what. Thanks in advance for your help.
You can use a recursive method to do the transformation:
changefun <- function(x, change_name, new_name){
idx <- names(x) == change_name
if(any(idx)) names(x)[idx] <- new_name
if (is.list(x)) lapply(x, changefun, change_name, new_name)
else x
}
Now just call
changefun(listbig, 'changethis', 'changed')

Trouble creating lists in R for the networkD3 package

I'd like to create the radial network above utilizing the R package networkD3. I read the guide here which utilizes lists to create radial networks. Unfortunately my R skills with lists are lacking. They're actually non-existent. Fortunately there's the R4DS guide here.
After reading everything I come up with this code below, to create the diagram above.
library(networkD3)
nd3 <- list(Start = list(A = list(1, 2, 3), B = "B"))
diagonalNetwork(List = nd3, fontSize = 10, opacity = 0.9)
Alas, my attempt fails. And subsequent attempts fail to generate anything that's close to the diagram above. I'm pretty sure it's my list that's wrong. Maybe you can show me the right list and things will start to make sense.
Jason!
The issue here is that the parameter nd3 has a very specific grammar of node name and children. So your code should look like this:
library(networkD3)
nd3 <- list(name = "Start", children = list(list(name = "A",
children = list(list(name = "1"),
list(name = "2"),
list(name = "3")
)),
list(name = "B")))
diagonalNetwork(List = nd3, fontSize = 10, opacity = 0.9)
If you're like me and the data frame/spreadsheet format is easier to wrap your head around, you could build an easy data frame with your data and then use data.tree functions to convert it to the list/json format...
library(data.tree)
library(networkD3)
source <- c("Start", "Start", "A", "A", "A")
target <- c("A", "B", "1", "2", "3")
df <- data.frame(source, target)
nd3 <- ToListExplicit(FromDataFrameNetwork(df), unname = T)
diagonalNetwork(List = nd3, fontSize = 10, opacity = 0.9)

R: Create nested list from IDs in character vector

I have a character vector of hierarchical IDs like this one:
ids <- c("0","1","2","3","1.1","1.2","1.3","2.1","2.2","2.11","2.21","2.22")
The hierarchical structure is as follows:
1
1.1
1.2
1.3
2
2.1
2.11
2.2
2.21
2.22
I want to use diagonalNetwork() from the networkD3 package to visualize this hierarchy. But diagonalNetwork() requires a nested list defining each nodes children like this one:
l <- list(name = "0",
children = list(
list(name = "1",
children = list(
list(name = "1.1"),
list(name = "1.2"),
list(name = "1.3")
)
),
list(name = "2",
children = list(
list(name = "2.1",
children = list(
list(name = "2.11")
)
),
list(name = "2.2",
children = list(
list(name = "2.21"),
list(name = "2.22")
)
)
)
)
)
)
My actual set of ids is much larger and deeper (up to 6 digits long), so I need a way to create this nested list automatically. I started with creating a data.frame that stores the ids' digits in several columns like this one:
df <- data.frame(root = 0,
a = c( 1, 1, 1, 1, 2, 2, 2, 2, 2, 2),
b = c(NA, 1, 2, 3,NA, 1, 1, 2, 2, 2),
c = c(NA,NA,NA,NA,NA,NA, 1,NA, 1, 2))
But I can't think of a way to get any further with my concern.
Is there a more promising approach?
Here is a possible solution based on recursive function. And it is by no means a fast solution but should work for you.
library(network3D)
findChildren <- function(pa, ids) {
lapply(ids, function(ch){
if(grepl(paste("^", pa, sep = ""), ch) && ch != pa &&
nchar(gsub("\\.", "", ch)) == nchar(gsub("\\.", "", pa)) + 1)
{
childrenTmp = Filter(Negate(is.null), findChildren(ch, ids))
if(length(childrenTmp) != 0) list(name = ch, children = childrenTmp)
else list(name = ch)
}
}
)
}
myList <- list(name = "0",
children = Filter(
function(x){nchar(x$name) == 1 },
lapply(ids[-1], function(id) {
childrenTmp = Filter(Negate(is.null), findChildren(id, ids))
if(length(childrenTmp) != 0) list(name = id, children = childrenTmp)
else list(name = id)
}
)
)
)
diagonalNetwork(myList)

Resources