Python: sorting elements from two values ​​(one must overlap and the other must not) into four cells

Ok, I'm thinking about how to solve this problem. In each semester, I need to find a way to sort 5-20 tests, which are given to 5-20 students during the four available days for the tests. My task is to try to collect all the tests of the same type on the same day, if possible, and also make sure that no student is assigned to two tests on the same day.

The list I get looks like this: S is a student, and T is the test they want to take:

S1:T1
S1:T2
S2:T1
S2:T3
S2:T4
S3:T1
S3:T2
S4:T3
S5:T2
S5:T3
etc.

What I want to do is sort all T2 for a given day - A, B, C, D - and make sure that the student, for example, S5 above, also does not conduct another test that day.

, , , , , ... fu.

, , , , , , , T1 T4 A, T2 - B.

, - , - , .

+4
2

, , . , , , , , , .

, students tests.

students, tests = zip(*map(lambda each: each.split(':'), data.split()))

data - , , . , .

unique_tests = set(tests)
test_map = {test : set() for test in unique_tests}
for student, test in zip(students, tests):
    test_map[test].add(student)

test_map :

{'T1': {'S1', 'S2', 'S3'},
'T2': {'S1', 'S3', 'S5'},
'T3': {'S2', 'S4', 'S5'},
'T4': {'S2'}}

.

import itertools
test_combos = list(itertools.chain.from_iterable(
        (itertools.combinations(unique_tests, i) for i in
        range(2, len(unique_tests) + 1))))

test_combos:

[('T4', 'T3'),
('T4', 'T1'),
('T4', 'T2'),
('T3', 'T1'),
('T3', 'T2'),
('T1', 'T2'),
('T4', 'T3', 'T1'),
('T4', 'T3', 'T2'),
('T4', 'T1', 'T2'),
('T3', 'T1', 'T2'),
('T4', 'T3', 'T1', 'T2')]

, -1, 4 4 . , , .. , . ( , "" .)

, , True, . , , , , .

def valid_test_combo(tests):
    pairs = itertools.combinations(tests, 2)
    return all(map(lambda pair:
            test_map[pair[0]].isdisjoint(test_map[pair[1]]), pairs))

, :

valid_combos = set(filter(valid_test_combo, test_combos))
{('T4', 'T2')}

, , 'T2' 'T4'.

, , , :

combined_tests = set(itertools.chain.from_iterable(valid_combos))
remaining_tests = unique_tests - combined_tests
days = list(valid_combos) + list(remaining_tests)

days , :

[('T4', 'T2'), 'T3', 'T1']

:

, , set-cover problem, (NP-hard). , , , , .

+4

, . , , . , . , . , - , /. .

import operator

class NotAssigned(Exception):
    pass

students_tests = ['S1:T1','S1:T2','S2:T2','S2:T12','S2:T3','S2:T4','S3:T1','S3:T2','S4:T2','S4:T3','S5:T2','S5:T3','S6:T5','S6:T7']
days = [1,2,3,4]
final_plan = []
st_tup = []#Splitted Students_Tests
for st in students_tests:
    st_tup.append(tuple(st.split(":")))
students,tests = zip(*st_tup)

for i in range(len(students)):
    if i > 0:
        success = False
        d,s,t = zip(*final_plan)
        t_stats = {}#Get count of specific test on each day
        #Generate sorting sequence
        if tests[i] not in t:
            sort = days
        else:
            for day in days:
                t_stats[day] = 0
            for k in range(len(t)):
                if t[k] == tests[i]:
                        t_stats[d[k]] += 1
            sort = sorted(t_stats.items(), key=operator.itemgetter(1), reverse=True)
        try:
            for day in t_stats:
                if tuple([day,tests[i]]) in list(zip(d,t)):#Test already has been assigned for this day
                    if tuple([day,students[i]]) not in list(zip(d,s)):#Student doesn't have test this day
                        final_plan.append([day,students[i],tests[i]])
                        success = True
                        break
            if success == False:
                for day in days:
                    if tuple([day,students[i]]) not in list(zip(d,s)):#Student doesn't have test this day
                        final_plan.append([day,students[i],tests[i]])
                        success = True
                        break
            if success == False:
                raise NotAssigned
        except NotAssigned:
            print("Couldn't find suitable day for student " + students[i] + " for test " + tests[i])
    else:
        final_plan.append(list([days[0],students[0],tests[0]]))

print (final_plan)
+1

Source: https://habr.com/ru/post/1689982/


All Articles