在R中使用递归函数构建ID与主键的网络/连通关联分组
问题分析
这个需求本质是求二部图的连通分量:ID和Key是两类节点,ID与它关联的Key之间存在边,所有连通的节点属于同一组,最终提取每个组中的所有Key即可。
你编写的递归函数主要存在两个逻辑漏洞:
- 循环中只要遇到第一个和最后一个元素无交集的ID组就直接
return,没有遍历完所有可合并的ID组,漏了大量合并场景 - 合并后没有对Key去重,也没有处理合并后和其他ID组新增的交集情况
实现方案
方案1:使用igraph包(最简洁稳定)
直接通过图连通分量计算,代码量少且不易出错:
library(igraph) # 避免因子类型干扰,先转字符 dt$ID <- as.character(dt$ID) dt$Key <- as.character(dt$Key) # 构建无向二部图 g <- graph_from_data_frame(dt, directed = FALSE) # 计算连通分量 clu <- components(g) # 提取所有Key对应的分组,过滤掉ID节点 key_nodes <- unique(dt$Key) key_groups <- split(key_nodes, clu$membership[key_nodes]) # 可选:把Key转回数值类型 key_groups <- lapply(key_groups, as.numeric)
方案2:基础R迭代实现(无需第三方包)
纯基础R语法,通过迭代合并的方式完成分组:
# 第一步:每个ID对应的Key去重,存储为列表 id_key <- lapply(split(dt$Key, dt$ID), unique) groups <- list() while(length(id_key) > 0) { # 取第一个ID的Key作为初始分组 current_group <- id_key[[1]] id_key <- id_key[-1] changed <- TRUE # 迭代合并所有和当前组有交集的ID对应的Key while(changed) { changed <- FALSE for(i in seq_along(id_key)) { if(length(intersect(current_group, id_key[[i]])) > 0) { current_group <- union(current_group, id_key[[i]]) id_key <- id_key[-i] changed <- TRUE break } } } # 合并完成的组存入结果 groups[[length(groups)+1]] <- sort(current_group) }
示例数据运行结果
两种方案运行你提供的示例数据,最终得到2个分组:
- 分组1:
1,2,3,4,7,8,9,11,15,17,18 - 分组2:
5
内容的提问来源于stack exchange,提问作者Ahad Zaman
相关产品推荐
相关产品推荐

