SAS EG如何实现多列循环拼接 列数超5时按规则合并为5列
SAS EG 动态列拼接实现方案
需求规则
- 每行有效列数≤5时,c1-c5列值保持原样,无效值统一为
"-" - 有效列总数随数据定期刷新动态变化(上限约20列),每行已通过
count字段标注当前行有效列数 - 有效列数>5时,按对应步长将所有有效列值拼接后仅保留c1-c5共5列,步长匹配规则:
- 5<count≤10:步长2,每2个有效值拼接为1个新列值
- 10<count≤15:步长3,每3个有效值拼接为1个新列值
- 15<count≤20:步长4,每4个有效值拼接为1个新列值
- 20<count≤25:步长5,规则以此类推
- 拼接分隔符为英文逗号+空格
", ",不足整步长的剩余有效值直接放入最后一个有值的c列,无值的c列填充"-"
输入输出样例:
输入包含c1-c8共8个值列及count字段:第一行c1-c5有值、c6-c8为"-",count=5;第二行c1-c8均为有效值,count=8。
期望输出仅保留c1-c5列:第一行取值与原c1-c5完全一致;第二行c1为"string1, string2"、c2为"string3, string4"、c3为"string5, string6"、c4为"string7, string8"、c5为"-"。
原有代码问题
- 宏逻辑与数据步逻辑混用:
%sysfunc、宏%do循环在SAS编译阶段执行,无法逐行读取数据步中动态变化的count值,不能实现按行分支判断 - 变量引用逻辑错误:宏变量拼接、列变量定位写法不规范,无法正确读取c列值
- 缺少分区间步长判断的分支逻辑,未配置无效值默认填充规则
可直接运行的实现代码
data want; set have; /* 定义原始值列数组,上限设为20覆盖现有业务场景,后续列数增加仅需修改数组末尾的列序号即可 */ array orig_c[*] c1-c20; /* 定义输出的5个目标列,设置足够长度存储拼接后的字符串 */ array target_c[5] $200. c1-c5; /* 初始化所有目标列默认值为"-" */ do i = 1 to 5; target_c[i] = "-"; end; if count <= 5 then do; /* 有效列数≤5时直接保留原值 */ do i = 1 to count; target_c[i] = orig_c[i]; end; end; else do; /* 自动计算步长:ceil(count/5)完全匹配分区间步长规则,无需手写多层if判断 */ step = ceil(count/5); pos = 1; /* 标记当前读取原始列的起始位置 */ do i = 1 to 5 while(pos <= count); /* 计算当前组的结束列位置,最后一组不足步长时取到最后一个有效列即可 */ end_pos = min(pos + step - 1, count); cat_str = ""; /* 拼接当前组的所有列值 */ do j = pos to end_pos; cat_str = catx(", ", cat_str, orig_c[j]); end; target_c[i] = cat_str; pos = end_pos + 1; end; end; /* 保留输出字段,如需保留其他业务字段可在keep后追加 */ keep c1-c5; run;
逻辑说明
- 步长通过
ceil(count/5)自动计算:count为6-10时返回值为2,11-15时返回值为3,16-20时返回值为4,完全匹配设定的区间规则,后续count上限提升也无需新增判断分支 - 所有循环、分支判断均在数据步内执行,可逐行读取每行的count值动态计算,不依赖宏预编译逻辑,运行稳定性更高
- 提前初始化目标列默认值为
"-",无需额外判断空值填充,拼接完成后剩余无值的c列会自动保留默认值 - 原始列数组长度预留至c20,后续如果有效列上限提升,仅需修改
array orig_c[*] c1-c20中的列序号上限即可,无需调整其他逻辑
内容的提问来源于stack exchange,提问作者sassane
相关产品推荐
相关产品推荐

