Bash按连续步长分组排序数字数组的函数异常排查
问题排查与修复
需求说明
对Bash数字数组按以下规则分组排序:
- 优先排列步长为1、长度≥3的连续序列
- 接着是步长为2的同类序列,以此类推
- 最后放置无法组成长度≥3连续序列的元素
示例输入数组:
a=( 1 6 8 15 22 32 34 36 24 25 26)
预期排序结果:
b=(24 25 26; 32 34 36; 1 8 15 22; 6)
现有问题
执行原函数group_jobs_for_pbs后得到结果:
24 25 26;32 34 36;8 15 22; 1
存在两个问题:
- 数字
1未被归入步长为7的序列1 8 15 22 - 数字
6被意外遗漏
问题根源
- 初始
prev值错误:原函数初始prev=0,导致第一个元素1直接被判定为不匹配任何步长,无法进入正确的序列分组 - 序列遍历逻辑缺陷:从第一个元素开始遍历但未正确初始化分组,导致部分元素被错误丢弃
- 剩余元素传递逻辑不严谨:步长循环中对未分组元素的传递存在遗漏风险
修复后的函数
function group_jobs_for_pbs { local jobnos=("${@}") # 排序数字数组 local sortedjobno=() while IFS='' read -r line; do sortedjobno+=("$line"); done < <(printf '%s\n' "${jobnos[@]}" | sort -g) local ars=() local remaining=("${sortedjobno[@]}") # 遍历步长1到10 for step in $(seq 1 10); do if [[ ${#remaining[@]} -lt 3 ]]; then break fi local current_group=() local new_remaining=() local prev=${remaining[0]} current_group+=("$prev") # 从第二个元素开始遍历匹配步长 for ((i=1; i<${#remaining[@]}; i++)); do local curr=${remaining[i]} if (( 10#$curr == 10#$prev + step )); then current_group+=("$curr") else # 处理当前分组:满足长度则加入结果,否则归入剩余元素 if [[ ${#current_group[@]} -ge 3 ]]; then ars+=("${current_group[*]}") else new_remaining+=("${current_group[@]}") fi current_group=("$curr") fi prev=$curr done # 处理最后一个分组 if [[ ${#current_group[@]} -ge 3 ]]; then ars+=("${current_group[*]}") else new_remaining+=("${current_group[@]}") fi # 更新剩余元素,进入下一步长检查 remaining=("${new_remaining[@]}") done # 处理剩余无法组成长度≥3的元素 while [[ ${#remaining[@]} -gt 0 ]]; do if [[ ${#remaining[@]} -ge 2 ]]; then ars+=("${remaining[0]} ${remaining[1]}") remaining=("${remaining[@]:2}") else ars+=("${remaining[0]}") remaining=() fi done # 转换为分号分隔的字符串 IFS=';' retjobstr="${ars[*]}"; unset IFS echo "${retjobstr}" }
验证结果
执行命令:
$ group_jobs_for_pbs 1 6 8 15 22 32 34 36 24 25 26
输出结果:
24 25 26;32 34 36;1 8 15 22;6
完全符合预期要求。
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

