如何封装R函数,使其循环调用自身输出直至输入输出长度一致?
问题描述
我正在处理多字段的杂乱业主数据,示例数据如下:
library(tidyverse) df <- structure(list(id = c("0049984000", "3502234000", "4029979100", "4331301000", "4690309000", "4690487000", "4690686000", "4702065000", "4980108200"), OWNER_NAME_1 = c("CLAUDEAN L RING REV TRUST", "S2 REAL ESTATE GROUP 5 LLC", "SAM STAIR", "S2 REAL ESTATE GROUP", "S2 REAL ESTATE GROUP 5 LLC", "S2 REAL ESTATE GROUP 5 LLC", "S2 REAL ESTATE GROUP 5 LLC", "S2 REAL ESTATE", "S2 REAL EST GROUP"), OWNER_MAIL_ADDR = c("2045 PARADISE DR", "11512 W WOODSIDE DR", "2925 W LINCOLN AVE", "2925 W LINCOLN AVE", "2925 W LINCOLN AV", "2925 W LINCOLN AVE", "2925 W LINCOLN AV", "11512 W WOODSIDE DR", "2925 W LINCOLN AVE"), OWNER_CITY_STATE = c("WEST BEND, WI", "HALES CORNERS, WI", "MILWAUKEE, WI", "MILWAUKEE, WI", "MILWAUKEE, WI", "MILWAUKEE, WI", "MILWAUKEE, WI", "HALES CORNERS, WI", "MILWAUKEE, WI" )), row.names = c(NA, -9L), class = c("tbl_df", "tbl", "data.frame" )) df # A tibble: 9 × 4 id OWNER_NAME_1 OWNER_MAIL_ADDR OWNER_CITY_STATE <chr> <chr> <chr> <chr> 1 0049984000 CLAUDEAN L RING REV TRUST 2045 PARADISE DR WEST BEND, WI 2 3502234000 S2 REAL ESTATE GROUP 5 LLC 11512 W WOODSIDE DR HALES CORNERS, WI 3 4029979100 SAM STAIR 2925 W LINCOLN AVE MILWAUKEE, WI 4 4331301000 S2 REAL ESTATE GROUP 2925 W LINCOLN AVE MILWAUKEE, WI 5 4690309000 S2 REAL ESTATE GROUP 5 LLC 2925 W LINCOLN AV MILWAUKEE, WI 6 4690487000 S2 REAL ESTATE GROUP 5 LLC 2925 W LINCOLN AVE MILWAUKEE, WI 7 4690686000 S2 REAL ESTATE GROUP 5 LLC 2925 W LINCOLN AV MILWAUKEE, WI 8 4702065000 S2 REAL ESTATE 11512 W WOODSIDE DR HALES CORNERS, WI 9 4980108200 S2 REAL EST GROUP 2925 W LINCOLN AVE MILWAUKEE, WI
我已经编写了connect_owners_by_address函数,输入业主名称向量,返回所有共享地址的业主名称:
# 识别所有与给定名称共享地址的其他业主名称 connect_owners_by_address <- function(landlord_names){ # 获取给定业主名下的所有地址 addresses1 <- df %>% filter(OWNER_NAME_1 %in% landlord_names) %>% group_by(OWNER_MAIL_ADDR, OWNER_CITY_STATE) %>% summarise() %>% ungroup() # 获取这些地址关联的所有业主名称 names.at.addresses <- df %>% inner_join(addresses1, by = join_by(OWNER_MAIL_ADDR, OWNER_CITY_STATE)) %>% group_by(OWNER_NAME_1) %>% summarise() names.at.addresses$OWNER_NAME_1 }
递归调用该函数可以找到更多关联业主,但需要手动重复调用直到结果不再新增:
# 第一次调用(4个匹配结果) connect_owners_by_address("SAM STAIR") [1] "S2 REAL EST GROUP" "S2 REAL ESTATE GROUP" "S2 REAL ESTATE GROUP 5 LLC" "SAM STAIR" # 第二次调用(5个匹配结果) connect_owners_by_address("SAM STAIR") |> connect_owners_by_address() [1] "S2 REAL EST GROUP" "S2 REAL ESTATE" "S2 REAL ESTATE GROUP" "S2 REAL ESTATE GROUP 5 LLC" [5] "SAM STAIR" # 第三次调用(结果不再变化) connect_owners_by_address("SAM STAIR") |> connect_owners_by_address() |> connect_owners_by_address() [1] "S2 REAL EST GROUP" "S2 REAL ESTATE" "S2 REAL ESTATE GROUP" "S2 REAL ESTATE GROUP 5 LLC" [5] "SAM STAIR"
我需要把这个函数封装成一个新函数,让它自动循环调用,直到输出结果的长度和输入长度一致时停止,不知道如何用while循环实现这个逻辑。
解决方案
可以编写一个封装函数,用循环持续调用connect_owners_by_address,每次比较输入和输出的长度,直到两者相等(即没有新的业主被关联)就终止循环:
find_all_related_owners <- function(initial_names) { current_names <- initial_names repeat { # 调用函数获取新的关联业主 new_names <- connect_owners_by_address(current_names) # 去重并排序,避免顺序或重复值影响长度判断 current_names <- sort(unique(current_names)) new_names <- sort(unique(new_names)) # 如果当前结果和新结果长度一致,说明没有新增,退出循环 if (length(current_names) == length(new_names)) { break } # 更新当前结果为新结果,继续循环 current_names <- new_names } return(current_names) }
测试验证
调用这个封装函数测试:
find_all_related_owners("SAM STAIR") [1] "S2 REAL EST GROUP" "S2 REAL ESTATE" "S2 REAL ESTATE GROUP" "S2 REAL ESTATE GROUP 5 LLC" [5] "SAM STAIR"
逻辑说明
- 初始化
current_names为输入的初始业主名称 - 在循环中调用
connect_owners_by_address获取新的关联业主列表 - 对当前和新列表进行去重、排序,避免因顺序或重复值导致长度判断出错
- 比较两者的长度:如果相等,说明没有新的业主被找到,终止循环;否则更新
current_names为新列表,继续循环 - 最后返回最终的关联业主列表
内容的提问来源于stack exchange,提问作者John J.
相关产品推荐
相关产品推荐

