R语言循环中关联列表索引与对应cm值的实现问题
我来帮你解决这个问题!首先咱们先理清楚你遇到的两个核心问题:原代码的配对逻辑错误,以及你尝试获取bb名称时的写法问题。
问题1:原代码的配对错误原因
你的第一层循环遍历aa,第二层遍历所有bb的元素,这就导致只要某个bb元素符合any(cc %in% b)的条件,就会和当前aa里的cm值配对,完全忽略了aa里第一个元素是bb的索引名称这个对应关系。所以才会出现所有符合条件的bb项和每个cm都组合的情况。
问题2:names(bb)[b]写法错误的原因
当你在循环里写names(bb)[b]时,b是bb里的元素(比如c("a", "b", "c")),而不是bb的位置索引或者名称字符串。names(bb)是一个字符向量c("123", "234", "345", "456"),你用一个包含"a","b","c"的向量去索引它,自然找不到匹配的内容,只会返回NA,所以这个写法完全不生效。
正确的解决方案
我们需要让aa里的索引和bb的名称一一对应,只检查aa指定的bb元素是否符合条件,然后配对对应的cm值。这里有两种写法:
写法1:修正循环逻辑
直接遍历aa,取出每个元素的索引值,找到bb中对应的元素,再判断条件:
library("tidyverse") aa <- list(c(123, 1), c(234, 1), c(345, 2), c(456, 3)) bb <- list("123" = c("a", "b", "c"), "234" = c("b", "c", "d"), "345" = c("c", "d", "e"), "456" = c("f", "g", "h")) cc <- c("a", "b", "c") tbl <- NULL for (a in aa) { # 把aa里的数字索引转成字符,匹配bb的名称 bb_name <- as.character(a[1]) # 获取bb中对应名称的元素 target_b <- bb[[bb_name]] # 检查是否包含cc中的元素 if (any(cc %in% target_b)) { tb <- tibble(cm = a[2], n1 = target_b[1], n2 = target_b[2], n3 = target_b[3]) tbl <- bind_rows(tbl, tb) } } # 查看结果 tbl
运行后就会得到你期望的输出:
# A tibble: 3 x 4 cm n1 n2 n3 <dbl> <chr> <chr> <chr> 1 1 a b c 2 1 b c d 3 2 c d e
写法2:用tidyverse风格替代循环(更推荐)
如果你习惯tidyverse的写法,可以避免循环,通过数据框合并和过滤来实现:
library("tidyverse") aa <- list(c(123, 1), c(234, 1), c(345, 2), c(456, 3)) bb <- list("123" = c("a", "b", "c"), "234" = c("b", "c", "d"), "345" = c("c", "d", "e"), "456" = c("f", "g", "h")) cc <- c("a", "b", "c") # 把aa转换成包含索引和cm的数据框 aa_df <- aa %>% map_dfr(~tibble(idx = as.character(.x[1]), cm = .x[2])) # 把bb转换成包含索引和n1/n2/n3的数据框 bb_df <- bb %>% enframe(name = "idx") %>% unnest_wider(value, names_sep = "") # 合并两个数据框,过滤符合条件的行 output <- aa_df %>% inner_join(bb_df, by = "idx") %>% # 检查n1/n2/n3中是否包含cc的元素 filter(pmap_lgl(select(., starts_with("n")), ~any(cc %in% c(...)))) %>% select(cm, n1, n2, n3) output
这种写法更清晰,也更容易维护,结果和上面的循环写法一致。
内容的提问来源于stack exchange,提问作者ec1013
相关产品推荐
相关产品推荐

