兄弟们写了个取当前出现未达到占比且相差最大的类型的算法,但感觉不是很好

        $category_ids = [1,2,3];
        $categories_ratio = [3, 6, 1];
        $categories_count = [4, 12, 3];
        $all_zero = true;
        $is_surpass = false;
        $categories_zero_count = array();

        // 检查出现次数是否有0
        foreach ($categories_count as $key => $value) {
            if($value == 0){
                $categories_zero_count[$key] = $categories_ratio[$key];
            }
        }

        if(!empty($categories_zero_count)){
            $max_ratio = max($categories_zero_count);
            $max_ratio_key = array_keys($categories_zero_count, $max_ratio)[0];
            return $category_ids[$max_ratio_key];
        }

        // 计算每个元素的期望值
        $ratio_expected = array();
        foreach ($categories_ratio as $key => $value) {
            $ratio_expected[$key] = $value * $categories_count[0];
        }
        $count_expected = array();
        foreach ($categories_count as $key => $value) {
            $count_expected[$key] = $value * $categories_ratio[0];
        }
        // 计算每个元素的误差
        $ratio_error = array();
        $low_ratio = array();
        foreach ($ratio_expected as $key=> $value)
        {
            $ratio_error[$key] = $value - $count_expected[$key];
            if($ratio_error[$key] != 0){
                $all_zero = false;
            }
            $low_ratio[$key] = floor($ratio_error[$key]*100/$value);
            if($low_ratio[$key] > 0){
                // 存在超出
                $is_surpass = true;
            }
        }
        // 相差全为0,取占比最大的
        if($all_zero){
            $max_ratio = max($categories_ratio);
            $max_ratio_key = array_keys($categories_ratio, $max_ratio)[0];
            return $category_ids[$max_ratio_key];
        }
        // 比较,获取应该不足的
        if(!empty($low_ratio)){
            // 存在超出
            if($is_surpass){
                $max_error = max($low_ratio);
                $max_error_key = array_keys($low_ratio, $max_error)[0];
                return $category_ids[$max_error_key];
            }else{
                // 不存在超出取首个 如0,-12,-123
                return $category_ids[0];
            }
        }

        return array_rand( $category_ids );

$category_ids是分类id
$categories_ratio是对应分类的占比
$categories_count是对应分类出现的次数
理论上就是需要计算出当前出现的次数是否符合占比,选出没有达到占比的分类id,比如都没出现时,id 1出现了1次(正常应该是id2,它占比高),那么id1出现次数就为1: 0:0了,根据比例3, 6, 1,先去判断如果有出现次数为0的,按最大占比的返回,否则算首个相乘求出期望值和实际值,还没优化和严格验证,就先跑了几个测试,感觉是不是写的麻烦了,算法不好:sob:

需求如下:分类会有多种,每种分类都有对应的占比,比如ABC三类对应为2:4:6,每种分类出现过的次数会有记录,比如A,B,C各出现过2,4,6次那么认为当前是平衡状态,下一次预计出现的分类则为B类,因为平衡状态下,B类占比最大。当然一开始肯定不是平衡的,所以需要计算当前各类出现过的次数,根据占比返回每次应该出现的分类

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 10

你先说清楚你的需求, 我们才好判断写的到底好不好。

2年前 评论
Image 伽蓝幻梦 (楼主) 2年前
Image keyboby 2年前
Image 徵羽宫 (作者) 2年前
Image 徵羽宫 (作者) 2年前
Image 徵羽宫 (作者) 2年前
Image 徵羽宫 (作者) 2年前
Image 伽蓝幻梦 (楼主) 2年前

感觉是你想的复杂了
其实直接加权重随机即可,只要数据大这个数就是平均,你不能一组两组数据看。
还有一种每次按照最小单位制比如你的ABC三类对应位2:4:6 就是A:B:C就是1:2:3 就是1A2B3C累计6个 打乱扔到缓冲里一个一个取 没有再在按照比例往里面扔

2年前 评论
Image 伽蓝幻梦 (楼主) 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!