将函数应用于词典

2024-05-23 18:45:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我还在学习Python和这里的基本规则,所以如果我犯了错误,请纠正我。没有适当的批评和指导,一个人无法成长。你知道吗

我想帮我妻子安排一个募捐活动的志愿者日程。一天包含7个每小时一次的活动,我有7个每小时一次的时间表,让一个人为7个活动中的4个工作,供志愿者挑选。你知道吗

此代码所做的是根据我现有的志愿者数量,计算我需要满足活动志愿者要求的每个时间表的数量。我目前不知道她将有多少志愿者。你知道吗

import random
    # Volunteer Requirements for each of the 7 events
r = [6, 12, 14, 14, 12, 16, 10]
    # Available Schedules where 0 = hour off and 1 = hour working
s = []
s.append([0,1,1,1,1,0,0])
s.append([0,0,1,1,1,1,0])
s.append([0,0,0,1,1,1,1])
s.append([1,1,1,1,0,0,0])
s.append([1,1,0,0,0,1,1])
s.append([1,1,1,0,0,0,1])
s.append([1,0,0,0,1,1,1])

number_of_schedules = len(s)
number_of_vols = 21
number_of_hours = len(s[0])

while True:
    q = [0]*number_of_schedules
    for i in range(number_of_vols):
        q[random.randint(0,len(q)-1)] += 1
    t = [sum([q[j]*s[j][i] for j in range(number_of_schedules)]) for i in range(number_of_hours)]
    if sum([r[i] <= t[i] for i in range(number_of_hours)]) == number_of_hours:
        print '\n'.join(map(str,q))
        print '\n'.join(map(str,s))
        break

当我运行代码时,它打印为:

3
8
2
1
6
2
0
[0, 1, 1, 1, 1, 0, 0]
[0, 0, 1, 1, 1, 1, 0]
[0, 0, 0, 1, 1, 1, 1]
[1, 1, 1, 1, 0, 0, 0]
[1, 1, 0, 0, 0, 1, 1]
[1, 1, 1, 0, 0, 0, 1]
[1, 0, 0, 0, 1, 1, 1] 

这告诉我,为了满足要求,我将需要3个人采取第一时间表,8采取第二,2采取第三,以此类推。你知道吗

我要做的是将列表“s”构建为dict,这样我就可以为每个计划指定一个名称,即“计划a”、“计划B”等。这样我就可以调用print函数来打印每个计划所需的次数。你知道吗

当我调用print函数时,首选的最终结果如下所示。你知道吗

    Schedule A 
    Schedule A 
    Schedule B 
    Schedule B 
    Schedule B 
    Schedule B 
    Schedule B 
    ........
    Schedule G 

然后每个志愿者可以把他们的名字放在一个可用的时间表旁边。你知道吗

我遇到的问题是,无论我尝试什么方法,我都无法让它正常工作。我希望在周五之前完成,因为我妻子想在这个周末发一封志愿者请求邮件。任何人能提供的任何帮助/指导都将不胜感激。你知道吗

提前谢谢。你知道吗


Tags: ofinnumberforlenrange时间表计划
2条回答

如果你需要额外的速度或科学严谨,休·博思韦尔的解决方案是非常好的。它回答了一个没有被问到的问题。如果您对现在的计算方式感到满意,并且只希望能够打印计划名称而不是(或者除了)0和1的序列,那么就简单多了。你知道吗

你不可能用一个数字“乘”整本字典。有很多奇妙的方法来制作一个类似字典的对象,它会以你想要的方式工作,但是我认为这对于你想要完成的事情来说是过分的。你知道吗

它的技术含量很低,可能看起来也不优雅,但最简单的方法是创建另一个只包含计划名称的列表,其顺序与s相同。s中的给定索引将对应于名称列表中的相同索引。(如果不可能按顺序处理它们,可以使用.index()查找给定值的索引。例如,s.index([0, 0, 0, 1, 1, 1, 1])将返回2。)

出于兴趣,我将其编码为基因搜索:

import numpy as np
from random import choice, randrange
from string import ascii_uppercase

# volunteer requirements for each of the 7 events
NEEDED = np.array([6, 12, 14, 14, 12, 16, 10], dtype=np.int32)

# available schedules where 0 = hour off and 1 = hour working
SCHEDULES = np.array([
    [0,1,1,1,1,0,0],
    [0,0,1,1,1,1,0],
    [0,0,0,1,1,1,1],
    [1,1,1,1,0,0,0],
    [1,1,0,0,0,1,1],
    [1,1,1,0,0,0,1],
    [1,0,0,0,1,1,1]
], dtype=np.int32)

NAMES = ["Schedule {}".format(ch) for ch in ascii_uppercase[:len(SCHEDULES)]]

def alloc_random(num, schedules):
    """
    Create a random allocation of schedules
    """
    num_schedules = len(schedules)
    alloc = np.zeros(num_schedules, dtype=np.int32)
    for _ in range(num):
        alloc[randrange(num_schedules)] += 1
    return alloc

def alloc_mutate(alloc):
    """
    Randomly replace one schedule with another
    """
    alloc = np.copy(alloc)   # make a new allocation (instead of modifying the parent)
    num_schedules = len(alloc)
    while True:
        from_ = randrange(num_schedules)
        to_ = randrange(num_schedules)
        if from_ != to_ and alloc[from_] > 0:
            alloc[from_] -= 1
            alloc[to_] += 1
            return alloc

def alloc_fitness(alloc):
    """
    Given a schedule allocation,
      return the minimum (volunteers present / needed) of any period
    """
    return np.min(alloc.dot(SCHEDULES) / NEEDED)

def alloc_find_best(num_volunteers, needed, schedules, population=20, children=100, generations=1000):
    """
    Find the best way to assign schedules to volunteers
    """
    # generate starting population
    pop = [alloc_random(num_volunteers, schedules) for _ in range(population)]
    # evolve!
    for gen in range(generations):
        # create evolved children
        ch = [alloc_mutate(choice(pop)) for _ in range(children)]
        # add the parents to the evaluation pool
        ch.extend(pop)
        # sort from most to least fit
        ch.sort(key=alloc_fitness, reverse=True)
        # decimate
        pop = ch[:population]
    # return the best solution found
    return pop[0]

def main():
    for num_volunteers in range(21, 25):
        best = alloc_find_best(num_volunteers, NEEDED, SCHEDULES)
        print("\n{:>2d} volunteers:  fitness = {:0.1f}%".format(num_volunteers, 100. * alloc_fitness(best)))
        for label,val in zip(NAMES, best):
            print("{:>14s}: {:>2d}".format(label, val))

if __name__ == "__main__":
    main()

输出如下

21 volunteers:  fitness = 92.9%
    Schedule A:  4
    Schedule B:  7
    Schedule C:  2
    Schedule D:  0
    Schedule E:  6
    Schedule F:  2
    Schedule G:  0

22 volunteers:  fitness = 100.0%
    Schedule A:  3
    Schedule B:  8
    Schedule C:  2
    Schedule D:  1
    Schedule E:  6
    Schedule F:  2
    Schedule G:  0

23 volunteers:  fitness = 100.0%
    Schedule A:  2
    Schedule B:  9
    Schedule C:  2
    Schedule D:  2
    Schedule E:  6
    Schedule F:  2
    Schedule G:  0

24 volunteers:  fitness = 107.1%
    Schedule A:  4
    Schedule B:  9
    Schedule C:  2
    Schedule D:  0
    Schedule E:  7
    Schedule F:  2
    Schedule G:  0

有几个有趣的地方:

  • 只要把需要的志愿者名额加起来,你就至少需要84/4==21名志愿者

  • 运行几次表明,您至少需要22名志愿者才能真正安排好一切,至少需要24名志愿者才能在每个时间段都有空闲时间

  • 你随机发现的解决方案实际上与我得到的完全相同,但是我的算法运行得更快-0.8秒,而平均36秒(在我的测试中从12秒到86秒)。

为了得到你想要的最终结果格式

for name,num,sched in zip(NAMES, best, SCHEDULES):
    for _ in range(num):
        print(name + "  " + str(sched))

这就好像

Schedule A  [0 1 1 1 1 0 0]
Schedule A  [0 1 1 1 1 0 0]
Schedule A  [0 1 1 1 1 0 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule B  [0 0 1 1 1 1 0]
Schedule C  [0 0 0 1 1 1 1]
Schedule C  [0 0 0 1 1 1 1]
Schedule D  [1 1 1 1 0 0 0]
Schedule E  [1 1 0 0 0 1 1]
Schedule E  [1 1 0 0 0 1 1]
Schedule E  [1 1 0 0 0 1 1]
Schedule E  [1 1 0 0 0 1 1]
Schedule E  [1 1 0 0 0 1 1]
Schedule E  [1 1 0 0 0 1 1]
Schedule F  [1 1 1 0 0 0 1]
Schedule F  [1 1 1 0 0 0 1]

我还做了一些敏感性分析,比如

from collections import Counter
Counter(tuple(alloc_find_best(22, NEEDED, SCHEDULES)) for _ in range(100))

这给了

{
    (2, 8, 2, 2, 6, 2, 0): 32,
    (3, 8, 2, 1, 6, 2, 0): 39,
    (4, 8, 2, 0, 6, 2, 0): 29
}

也就是说,在100次试验中只发现了3种解决方案,第二种解决方案被发现的频率略高,但这三种解决方案的可能性大致相同。值得注意的是,它们之间的唯一区别是附表a和D==时隙1和5之间的权衡。你知道吗

相关问题 更多 >