python如何利用算法解决业务上的【分单问题】

2023-05-25 01:48:21    来源:博客园

分单是很多企业日常工作中非常典型的一项内容,它非常复杂,但同时又极为重要,如何合理的分单是企业管理中一个很重要的课题。


(资料图片)

之所以说分单很复杂,是因为影响单据该分给谁,分多少量这个事儿本身就有太多的影响因子;一旦管理者在分单的公平性上出现大的问题,厚此薄彼了,往大了讲,员工的做事积极性有可能都会被挫伤。

简单列举几类:

1、员工的技能矩阵;

2、员工的出勤数据;

3、各种类型单据的SPT(标准作业时间);

4、员工手中已有的单据量;

5、不同类型单据量的分布情况;

6、某种类型的单据不够分时,该优先分给谁;

7、每次单据的来件数量、来件的类型高度不确定;

8、当某种类型给某些员工少分了一些数量,如何在另外一些类型上尽量多分他一些,使得每个人分到的总量尽可能均衡;

9、单据的黑白名单策略(某些类型,某些申请人提的优先不分给哪些人,优先分给哪些人);

10、某个单据被被驳回过,如何在第二次分单时优先分给当初的处理人;

11、某些人可以同时处理两个环节,如何保证他不处理同一个单据的前后两个环节,避免内控管理失效;

12、多个领单小组共享某些流程端口,如何区分单据优先分给哪个组;

13、如何保证每个人能处理能力范围内的尽可能多的类型的单据,以确保员工的能力得到充分锻炼;

……

您瞅瞅,我觉没撒谎,这可一点都不简单。偏偏在小爬我的实际业务中,就被要求解决这么头疼的问题。但是你以为小爬我这就怕了?NO NO NO,需求越有挑战,小爬越高兴。

先说说如何解决每个人分配的单据量不均衡的问题,其中一种思路:我们把总单据量基于业务类型分成N组,然后基于每个员工能处理的业务类型和当天的出勤情况,找到能处理每种业务类型的人员列表,假设是M个人。我们可以利用算法,每次分单前将人员列表的顺序随机打乱,那么每次分单时,每个人都有一定概率出现在队列末尾,也就是单据不够分给他的情况,最终只要我们把N组类型的单据都分完时,大家的概率总体上是均衡的,不过概率的事儿没人能说它绝对公平。

下面这段代码,就可以完美地打乱某个列表的顺序,让它彻底重排:

import randomdef shuffle_list(lst):    """将列表的顺序随机打乱,得到一个新的列表"""    new_lst = lst[:]  # 复制原列表,否则会影响原列表    random.shuffle(new_lst)  # 打乱顺序    return new_lst

可是它依然不是绝对公平的,没法保证每个人分到的单据量尽可能一样多,因为它只是在模拟扔色子,寄希望于概率均匀分布。如何保证大家的数量相对公平呢?

我们不妨利用python的字典,存储每个人(key)已经分到的单据号的列表合集,把列表作为字典的Value。当我们在对某种类型的N个单据分给M个人时,就好比是发扑克牌,但是又不能简单去按顺序发牌,而是看谁手上的牌少,就优先把剩余的牌发给它,这样手上牌少的人,总是能被照顾,直到最后大家手上发到的牌数接近。如何知道这个特殊的字典中,到底哪个Key的牌最少(列表的长度最短)呢?您不妨参考下下面的算法。

def get_Dic_shortest_key(keyList,my_dict):    """根据输入的字典,字典的键对应的值都是一个列表,如果哪个键对应的列表的长度最短,则返回该键"""    shortest_key = None    shortest_length = float("inf")    for key, value in my_dict.items():        if key in keyList and len(value) < shortest_length:            shortest_key = key            shortest_length = len(value)    # Return the key with the shortest list value    return shortest_key

有了上面的算法,我们也就解决了每次的发牌优先分给谁的问题,怎么把牌发完到对的人手上,就不是个问题了,代码示例如下:

def seperate_list(lst,personList, personFormNumber_dic):    """    将一个列表拆分成n个子列表组成的二维列表,要求每个子列表元素的长度尽可能接近    :param lst: 待分配的单据号列表    :param personList: 可以参与此次分单的人员列表    :param personFormNumber_dic:字典结构,每个人key手上已有的单据列表value    :return: personFormNumber_dic 返回这个字典(每个人手上的单据清单)    """    m = len(lst)    for i in range(m):  # 从后往前遍历列表        targetPerson=""        targetPerson=get_Dic_shortest_key(personList,personFormNumber_dic)        for random_element in lst:            personFormNumber_dic[targetPerson].append(random_element)            lst.remove(random_element)            break    return personFormNumber_dic

希望这些对现实业务的思考和代码实现,能对您的工作有所启发。不管咋说,活到老,学到老。拒绝躺平,一起卷起来!

快来关注本公众号 获取更多爬虫、数据分析的知识!

关键词:

X 关闭

安阳曹操墓将于2022年5月正式对公众开放
时间·2021-12-29    来源·中新网
为什么这次寒潮南方降雪这么明显?
时间·2021-12-29    来源·新华社
山西绛县6名失踪者全部遇难 当地:已立案调查
时间·2021-12-29    来源·中新网

X 关闭