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

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

  简单列举几类:

    1、员工的技能矩阵;

    2、员工的出勤数据;

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

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

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

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

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

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

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

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

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

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

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

    ……

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

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

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

import random
def 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

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

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

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

05-25 09:47