You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化等比例组合筛选Bash脚本,降低计算耗时

优化Bash脚本:按频率等比例筛选14组5数组合

原方法的核心问题

随机试错的无限循环纯纯是浪费算力——100选14的组合数超过3万亿,靠随机抽选刚好匹配频率比例的概率极低,完全是做无用功。coproc在这里也派不上用场,因为当前瓶颈是算法逻辑,不是并行IO或多进程任务,强行用反而会增加复杂度。

优化思路

直接从「频率等比例」的核心要求出发,用统计预计算+贪心筛选+局部调整的逻辑替代随机试错:

  1. 先统计100组里每个数字的总出现次数,算出14组对应的目标出现次数(原次数 × 14/100,取整后微调保证总和合理)
  2. 用贪心算法先选14组,每次挑能让当前频率和目标偏差最小的组合
  3. 最后做局部微调,替换个别组合进一步缩小频率偏差

具体优化脚本

#!/bin/bash

# 假设原始100组数据存在文件groups.txt,每行是5个空格分隔的数字
# 示例格式:
# 1 3 5 7 9
# 2 4 6 8 10
# ...

# 第一步:统计原始100组的数字频率
declare -A freq_orig
total_groups=100
target_groups=14

while read -ra nums; do
    for n in "${nums[@]}"; do
        ((freq_orig[$n]++))
    done
done < groups.txt

# 第二步:计算每个数字的目标出现次数(等比例缩放)
declare -A freq_target
total_freq=0
for n in "${!freq_orig[@]}"; do
    # 四舍五入取整保证比例近似
    freq_target[$n]=$(( (freq_orig[$n] * target_groups + total_groups / 2) / total_groups ))
    ((total_freq += freq_target[$n]))
done
# 调整总频率,确保等于14×5=70(14组每组5个数)
diff=$((70 - total_freq))
while ((diff != 0)); do
    # 找频率偏差最大的数字调整
    max_dev=0
    adjust_num=""
    for n in "${!freq_target[@]}"; do
        dev=$((freq_orig[$n] * target_groups - freq_target[$n] * total_groups))
        if ((diff > 0 && dev > max_dev)) || ((diff < 0 && dev < max_dev)); then
            max_dev=$dev
            adjust_num=$n
        fi
    done
    ((freq_target[$adjust_num] += diff > 0 ? 1 : -1))
    ((diff += diff > 0 ? -1 : 1))
done

# 第三步:贪心筛选初始14组
selected=()
declare -A freq_current

# 定义计算当前频率偏差的函数(平方和越小越匹配)
calc_deviation() {
    local dev=0
    for n in "${!freq_target[@]}"; do
        local diff=$((freq_current[$n] - freq_target[$n]))
        ((dev += diff * diff))
    done
    echo $dev
}

# 循环选14组
while (( ${#selected[@]} < target_groups )); do
    best_dev=999999
    best_group=""
    # 遍历所有未选中的组
    while read -ra nums; do
        group_str="${nums[*]}"
        # 跳过已选中的组
        if [[ " ${selected[*]} " =~ " $group_str " ]]; then
            continue
        fi
        # 模拟加入该组后的频率偏差
        declare -A temp_freq=("${freq_current[@]}")
        for n in "${nums[@]}"; do
            ((temp_freq[$n]++))
        done
        temp_dev=0
        for n in "${!freq_target[@]}"; do
            diff=$((temp_freq[$n] - freq_target[$n]))
            ((temp_dev += diff * diff))
        done
        # 更新最优组
        if ((temp_dev < best_dev)); then
            best_dev=$temp_dev
            best_group=$group_str
        fi
        unset temp_freq
    done < groups.txt
    # 选中最优组,更新当前频率
    selected+=("$best_group")
    read -ra nums <<< "$best_group"
    for n in "${nums[@]}"; do
        ((freq_current[$n]++))
    done
done

# 第四步:局部调整(可选,进一步缩小偏差)
current_dev=$(calc_deviation)
for i in "${!selected[@]}"; do
    # 临时移除当前组
    removed_group="${selected[$i]}"
    read -ra removed_nums <<< "$removed_group"
    for n in "${removed_nums[@]}"; do
        ((freq_current[$n]--))
    done
    # 找能让偏差最小的替换组
    best_replace_dev=$current_dev
    best_replace_group=""
    while read -ra nums; do
        group_str="${nums[*]}"
        if [[ " ${selected[*]} " =~ " $group_str " ]]; then
            continue
        fi
        declare -A temp_freq=("${freq_current[@]}")
        for n in "${nums[@]}"; do
            ((temp_freq[$n]++))
        done
        temp_dev=0
        for n in "${!freq_target[@]}"; do
            diff=$((temp_freq[$n] - freq_target[$n]))
            ((temp_dev += diff * diff))
        done
        if ((temp_dev < best_replace_dev)); then
            best_replace_dev=$temp_dev
            best_replace_group=$group_str
        fi
        unset temp_freq
    done < groups.txt
    # 如果找到更好的替换,更新选中组和频率
    if [[ -n $best_replace_group && best_replace_dev < current_dev ]]; then
        selected[$i]="$best_replace_group"
        read -ra replace_nums <<< "$best_replace_group"
        for n in "${replace_nums[@]}"; do
            ((freq_current[$n]++))
        done
        current_dev=$best_replace_dev
    else
        # 没找到更好的,恢复原组
        for n in "${removed_nums[@]}"; do
            ((freq_current[$n]++))
        done
    fi
done

# 输出结果
echo "筛选出的14组:"
for group in "${selected[@]}"; do
    echo "$group"
done

echo -e "\n频率匹配情况:"
for n in $(printf "%s\n" "${!freq_target[@]}" | sort -n); do
    echo "数字$n: 目标${freq_target[$n]}次,实际${freq_current[$n]:-0}次"
done

关键优化点说明

  • 完全抛弃随机试错,用统计计算明确目标,再通过贪心+微调快速逼近要求,耗时从“无限长”压缩到毫秒级
  • 不需要coproc:当前场景是单进程的计算逻辑,coproc适合处理并行IO或独立子任务,强行用反而会增加进程通信开销
  • 用平方和计算频率偏差,确保整体匹配度最优,最后局部调整进一步缩小误差

内容的提问来源于stack exchange,提问作者Benjamin Thuret

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:07:10