Home > Software design >  Reorder the list's elements and create a new list in R
Reorder the list's elements and create a new list in R

Time:09-09

Hopefully someone could help me the following issue:

I have a list which I built in the following way:

ratios_example = list()
ratios_example[[1]] = c(1,2,3,4,5)
ratios_example[[2]] = c(8,9,3,2,1,4,5)

colors_example = list()
colors_example[[1]] = c("#FFF900","#FFFC00","#FFF500","#FFF900","#FFF500")
colors_example[[2]] = c("#FFF100","#FFA000","#FFDE00","#FFF500","#FFFC00","#FFFD00","#FFFD00")

colors_overall_example = list()

for(i in 1:length(ratios_example)) {

  colors_overall_example[[i]] = matrix(NA, nrow=length(ratios_example[[i]]), ncol=2)

  for(j in 1:length(ratios_example[[i]])) {

    colors_overall_example[[i]][j,] = c(colors_example[[i]][j], ratios_example[[i]][j])

  }

  colors_overall_example[[i]] = as.matrix(colors_overall_example[[i]])

  colnames(colors_overall_example[[i]]) = c("color","curve")

}

So in my list of interest called colors_overall_example there are two matrices with two columns each. I need to build a new list, which corresponds to the number of curves (9 in this case) where each element corresponds to the colors for each of the curves, following the order of how those curves appear in the initial list. Some of the curves have no color, so in this case I would have a list element NULL, like for example for curve 7. The first element of the desirable list would correspond to the colors of the curve 1: c("#FFF900", "#FFFC00"), the second element would contain the colors for the curve 2: c("#FFFC00","#FFF500").

It's been a long time I was trying to figure out how to create a new list containing this information.

Thanks anyone who will try to help!

CodePudding user response:

I'm sure there's a more elegant solution with one of the (m/t/l/s)apply functions, but here's a nested loop approach:

J = 2  #num of list elements
N = 9 # num of colors

newlist <- vector(mode="list", length=N)

for(i in 1:N) {
for(j in 1:J) {
    newlist[[i]] <- c(newlist[[i]], colors_example[[j]][which(ratios_example[[j]] == i)])
}
}

CodePudding user response:

You can bind these matrices (as data frames), then summarize the colors into a list, within each group defined by the curve:

library(dplyr)
df = bind_rows(lapply(colors_overall_example, as.data.frame)) %>% 
  group_by(curve) %>% 
  summarize(colors = list(color))

This gives you a dataframe like this:

  curve colors   
  <chr> <list>   
1 1     <chr [2]>
2 2     <chr [2]>
3 3     <chr [2]>
4 4     <chr [2]>
5 5     <chr [2]>
6 8     <chr [1]>
7 9     <chr [1]>

If you want it as a list of length 9 (number of curves), you can do this:

setNames(as.list(df$colors), paste0("curve",df$curve))

Output:

$curve1
[1] "#FFF900" "#FFFC00"

$curve2
[1] "#FFFC00" "#FFF500"

$curve3
[1] "#FFF500" "#FFDE00"

$curve4
[1] "#FFF900" "#FFFD00"

$curve5
[1] "#FFF500" "#FFFD00"

$curve8
[1] "#FFF100"

$curve9
[1] "#FFA000"

CodePudding user response:

Similar to @langtang's answer, I think you can bind everything to a data.frame, but you can split out each value using a factor to account for missing rows in the creation of the final list.

tmp <- as.data.frame(do.call(rbind, colors_overall_example))
split(
    tmp$color, 
    factor(tmp$curve, levels=seq(min(as.numeric(tmp$curve)), max(as.numeric(tmp$curve))))
)
#$`1`
#[1] "#FFF900" "#FFFC00"
# 
#$`2`
#[1] "#FFFC00" "#FFF500"
#
#$`3`
#[1] "#FFF500" "#FFDE00"
#
#$`4`
#[1] "#FFF900" "#FFFD00"
#
#$`5`
#[1] "#FFF500" "#FFFD00"
#
#$`6`
#character(0)
#
#$`7`
#character(0)
# 
#$`8`
#[1] "#FFF100"
#
#$`9`
#[1] "#FFA000"
  • Related