Как перебрать список списков, в то время как поднаборы списков основаны на переменной - PullRequest
1 голос
/ 29 марта 2019

У меня есть список списков, похожих на приведенный здесь пример с игрушкой.Я хотел бы перебрать этот список, чтобы получить новый список, в котором были удалены элементы на основе переменной.


dput (head (list)):

list(FEB_gems = list(GAME1 = structure(list(GAME1_Class = structure(c(2L, 
1L, 5L, 4L, 3L), .Label = c("fighter", "paladin", "rouge", "sorcerer", 
"wizard"), class = "factor"), GAME1_Race = structure(c(3L, 1L, 
4L, 3L, 2L), .Label = c("elf", "gnome", "human", "orc"), class = "factor"), 
GAME1_Alignment = structure(c(4L, 2L, 1L, 5L, 3L), .Label = c("CE", 
"CG", "LG", "NE", "NN"), class = "factor"), GAME1_Level = c(6, 
7, 6, 7, 7), GAME1_Alive = structure(c(1L, 1L, 1L, 1L, 1L
), .Label = "y", class = "factor")), class = "data.frame", row.names = c(NA, 
-5L)), GAME2 = structure(list(GAME2_Class = structure(c(3L, 5L, 
2L, 4L, 1L), .Label = c("bard", "cleric", "fighter", "monk", 
"wizard"), class = "factor"), GAME2_Race = structure(c(2L, 3L, 
2L, 4L, 1L), .Label = c("dwarf", "elf", "half-elf", "human"), class = "factor"), 
GAME2_Alignment = structure(c(4L, 2L, 1L, 5L, 3L), .Label = c("CE", 
"CG", "LG", "NE", "NN"), class = "factor"), GAME2_Level = c(5, 
5, 5, 5, 5), GAME2_Alive = structure(c(1L, 2L, 2L, 2L, 2L
), .Label = c("n", "y"), class = "factor")), class = "data.frame", row.names = c(NA, 
-5L))), MAR_gems = list(GAME3 = structure(list(GAME3_Class = structure(c(2L, 
1L, 5L, 4L, 3L), .Label = c("barbarian", "cleric", "monk", "ranger", 
"warlock"), class = "factor"), GAME3_Race = structure(c(2L, 3L, 
2L, 4L, 1L), .Label = c("dwarf", "elf", "half-elf", "human"), class = "factor"), 
GAME3_Alignment = structure(c(2L, 2L, 1L, 3L, 2L), .Label = c("CE", 
"LG", "LN"), class = "factor"), GAME3_Level = c(1, 1, 1, 
1, 1), GAME3_Alive = structure(c(2L, 2L, 2L, 1L, 2L), .Label = c("n", 
"y"), class = "factor")), class = "data.frame", row.names = c(NA, 
-5L)), GAME4 = structure(list(GAME4_Class = structure(c(2L, 1L, 
5L, 4L, 3L), .Label = c("fighter", "paladin", "rouge", "sorcerer", 
"wizard"), class = "factor"), GAME4_Race = structure(c(2L, 3L, 
 2L, 4L, 1L), .Label = c("dwarf", "elf", "half-elf", "human"), class = "factor"), 
GAME4_Alignment = structure(c(1L, 2L, 1L, 4L, 3L), .Label = c("CE", 
"CG", "LG", "LN"), class = "factor"), GAME4_Level = c(5, 
5, 5, 5, 5), GAME4_Alive = structure(c(1L, 2L, 2L, 2L, 2L
), .Label = c("n", "y"), class = "factor")), class = "data.frame", row.names = c(NA, 
-5L))))

Я предпринял некоторую попытку вручную настроить список списков вручную.Функция будет предпочтительнее, потому что у меня есть несколько типов данных для подмножества.

1) поднабор столбцов уровня на основе интергера

df1 <- Games.Split[[1]][[1]]
Level <- df1[which(df1[4] > 6),]
Games.Split[[1]][[1]] <- Level

df1:

  GAME1_Class GAME1_Race GAME1_Alignment GAME1_Level GAME1_Alive
1     paladin      human              NE           6           y
2     fighter        elf              CG           7           y
3      wizard        orc              CE           6           y
4    sorcerer      human              NN           7           y
5       rouge      gnome              LG           7           y

Уровень:

 GAME1_Class GAME1_Race GAME1_Alignment GAME1_Level GAME1_Alive
2     fighter        elf              CG           7           y
4    sorcerer      human              NN           7           y
5       rouge      gnome              LG           7           y

2) subAlive-столбцы на основе строки

df2 <- Games.Split[[1]][[2]]
Alive <- df2[which(df2[5] == 'y'),]
Games.Split[[1]][[2]] <- Alive

df2:

 GAME2_Class GAME2_Race GAME2_Alignment GAME2_Level GAME2_Alive
1     fighter        elf              NE           5           n
2      wizard   half-elf              CG           5           y
3      cleric        elf              CE           5           y
4        monk      human              NN           5           y
5        bard      dwarf              LG           5           y

Alive:

 GAME2_Class GAME2_Race GAME2_Alignment GAME2_Level GAME2_Alive
2      wizard   half-elf              CG           5           y
3      cleric        elf              CE           5           y
4        monk      human              NN           5           y
5        bard      dwarf              LG           5           y

Однако я изо всех сил пытаюсь реализовать это вЦикл for для выполнения этих поднаборов задач по всему списку.

for (i in Games.Split){
  for (j in i){
    Alive = j[which(j[5] == 'y'),]
    j <- Alive
  }
}

В целом, функция / метод, который может выполнять итерацию по всему списку для предоставления нового списка, в котором больше нет удаленныхэлементы.

Ответы [ 3 ]

2 голосов
/ 29 марта 2019

Поскольку у вас есть два уровня списков для организации фреймов данных, для этого потребуется функция применения вложенных списков (lapply) - такая же, как цикл, но немного лучше.Вот пример, который создает функцию для поднабора списка игр (gameList) на основе максимального уровня (maxLevel):

listSubset <- function(x, maxLevel){
  lapply(x, function(ls){
    lapply(ls, function(df) df[df[[grep('Level', names(df), value = TRUE)]] < maxLevel, ])
  })
}
listSubset(x = gameList, maxLevel = 6)

Вывод:

$`FEB_gems`
$`FEB_gems`$`GAME1`
[1] GAME1_Class     GAME1_Race      GAME1_Alignment GAME1_Level     GAME1_Alive    
<0 rows> (or 0-length row.names)

$`FEB_gems`$GAME2
  GAME2_Class GAME2_Race GAME2_Alignment GAME2_Level GAME2_Alive
1     fighter        elf              NE           5           n
2      wizard   half-elf              CG           5           y
3      cleric        elf              CE           5           y
4        monk      human              NN           5           y
5        bard      dwarf              LG           5           y


$MAR_gems
$MAR_gems$`GAME3`
  GAME3_Class GAME3_Race GAME3_Alignment GAME3_Level GAME3_Alive
1      cleric        elf              LG           1           y
2   barbarian   half-elf              LG           1           y
3     warlock        elf              CE           1           y
4      ranger      human              LN           1           n
5        monk      dwarf              LG           1           y

$MAR_gems$GAME4
  GAME4_Class GAME4_Race GAME4_Alignment GAME4_Level GAME4_Alive
1     paladin        elf              CE           5           n
2     fighter   half-elf              CG           5           y
3      wizard        elf              CE           5           y
4    sorcerer      human              LN           5           y
5       rouge      dwarf              LG           5           y

Все функции находятся в базеR, поэтому не нужно устанавливать и изучать новые пакеты.

1 голос
/ 29 марта 2019

Я бы сказал, что жизнь будет проще, если вы реструктурируете свои данные, а затем используйте dplyr filter, чтобы извлечь то, что вы хотите (или опустить то, что вы не хотите).Предполагая, что ваши исходные данные называются foo:

# Load libraries
library(dplyr)
library(purrr)

# Remove one list
bar <- unlist(foo, recursive = FALSE)

# Get names of campaigns and games
campaign_games <- data.frame(do.call(rbind, strsplit(names(bar), "\\.")))

# Add campaigns and games numbers to data frames
ls_games <- pmap(list(campaign_games[, 1], campaign_games[, 2], bar), cbind)

# Rename all columns
ls_games <-  lapply(ls_games, function(x){names(x) <- c("Campaign", "Game_n", "Class", "Race", "Alignment", "Level", "Alive"); x})

# Convert to data frame
df <- bind_rows(ls_games)

# Look at result
head(df)

Теперь ваши данные выглядят так:

#   Campaign Game_n    Class  Race Alignment Level Alive
# 1 FEB_gems  GAME1  paladin human        NE     6     y
# 2 FEB_gems  GAME1  fighter   elf        CG     7     y
# 3 FEB_gems  GAME1   wizard   orc        CE     6     y
# 4 FEB_gems  GAME1 sorcerer human        NN     7     y
# 5 FEB_gems  GAME1    rouge gnome        LG     7     y
# 6 FEB_gems  GAME2  fighter   elf        NE     5     n

, что легко обрабатывается.Например, вытащите тех, кто жив в игре 1 из драгоценных камней FEB и имеет уровень 7 или выше.

df %>% filter(Alive == "y", Campaign == "FEB_gems", 
              Level >= 7, Game_n == "GAME1")

#   Campaign Game_n    Class  Race Alignment Level Alive
# 1 FEB_gems  GAME1  fighter   elf        CG     7     y
# 2 FEB_gems  GAME1 sorcerer human        NN     7     y
# 3 FEB_gems  GAME1    rouge gnome        LG     7     y
1 голос
/ 29 марта 2019

Если имеется только два вложенных list с и требуется другое filter условие, примените к нему индивидуально и присвойте выход обратно элементу list.Проходим по мастеру list с помощью map и затем применяем логические условия

library(purrr)
library(dplyr)
lst2 <- map(lst1, ~  {
       .x[[1]] <- .x[[1]] %>%
                       filter_at(4, all_vars(. > 6))
       .x[[2]] <- .x[[2]] %>%
                      filter_at(5, all_vars(. == 'y'))
         .x
    })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...