Pull to refresh

Comments 13

Я правильно понимаю что эта задача сводится к


Дано n множеств N1, N2,… Nn: ∀1 ≤ k ≤ n |Nk| ≥ 1
Найти множества: |Nk ⋂ Nj| ≥ max(|Nk|, |Nj|) / 2: j ≠ k


?


Потому что в этом случае решение укладывается в 3 строки:


import itertools

# данные, каждая цифра соотвествует директору
data = (
    {1, 2, 3, 4}, 
    {1, 2, 3, 5}, 
    {3, 4, 5, 6, 7}
)

# решение
for s0, s1 in itertools.combinations(data, 2):
    if len(s0 & s1) > max(len(s0), len(s1)) / 2:
        print(s0 & s1)
Общий смысл задачи: проверить, что любые 3 директора из 5 предложенных пользователем должны находиться в строке с директорами общества.

Спасибо! Но ведь тогда всё ещё проще:


# предложенные директора
managers_of_interest = {1, 2, 3} 

data = (
    {1, 2, 3, 4}, 
    {1, 2, 3, 5}, 
    {3, 4, 5, 6, 7}
)

for s in data:
    if managers_of_interest & s:
        print(s)

A в предыдущем примере так и вообще ничего вводить не надо — программа сама найдёт все организации в которых пересечение директоров больше 50%. И уже в этом результате имеет смысл искать конкретные имена.

По 1-му коду:
да, он выявил, что есть пересечение по 1,2,3, но в каких обществах не указал.
Кроме того, пользователь вводит 5-ть человек, а не троих. Из этих 5-х надо понять кто трое есть в строке с обществом в любой комбинации.
По 2-му коду.
Вывод:
{1, 2, 3, 4}
{1, 2, 3, 5}
{3, 4, 5, 6, 7}
Но в третьей строке нет пересечения! Там нет троицы «1,2,3».

Поторопился:


...
if managers_of_interest.issubset(s)

По 1-му коду — ну да, это лишь "заготовка" демонстрирующая основную идею. К ней можно приделать и красивый вывод и вообще всё что угодно :)

В таком случае рискну предположить, что сам python всего лишь заготовка, демонстрирующая основную идею )
как то так
def myfun(x, y, z):
    # получим множество кортежей с директорами
    directors = set(tuple(x.value for x in sheet['C2':'L36'].rows))
    # Получим список всех идентификаторов организаций
    companies = tuple(x.value for x in sheet['А2':'A36'])

    data_dict = dict(zip(companies, directors))

    checked_directors = set(x, y, z)

    for key, value in data_dict:
        if checked_directors.issubset(value):
            h.write(str(key) + '\n')
Пока ошибка:
directors = set(tuple(x.value for x in sheet['B2':'L36'].rows))
AttributeError: 'tuple' object has no attribute 'rows'
Библиотеку было лень ставить так что в слепую код писал. Главное смысл вы поняли надеюсь)
Уверен, что задача имеет более изящное решение. Но ваш код не удалось прокачать, хотя все библиотеки стоят. Если вы доведете до ума, буду очень благодарен.
Думаю в таком виде будет более изящное решение, и чуть более наглядное чем в статье.
Плюс учитывается что при заполнении таблицы имеются дубликаты ФИО (как в файле, когда один человек встречается 2 раза) и в таком случае он не добавляется в СД.

Код
def find_managers(inp_list, search_manages, min_find=3, skip_dupl=True):
    main_dict = {}
    for x in inp_list:
        i = 0
        for j in x:
            if i == 0:
                company_name = j
                main_dict[company_name] = {}
                main_dict[company_name]["managers"] = []
                main_dict[company_name]["count"] = 0
                main_dict[company_name]["searh_managers"] = []
                main_dict[company_name]["searh_count"] = 0
                main_dict[company_name]["searh_share"] = 0
                i += 1
            else:
                if isinstance(j, str):
                    bAdd = True
                    if skip_dupl:
                        if j in main_dict[company_name]["managers"]:
                            print(f"Дубликат {j} в членах СД компании {company_name}")
                            bAdd = False
                    if bAdd:
                        main_dict[company_name]["managers"].append(j)
                        if j in search_manages:
                            main_dict[company_name]["searh_managers"].append(j)
                            main_dict[company_name]["searh_count"] += 1
                        main_dict[company_name]["count"] += 1

        if min_find >= 0:
            if main_dict[company_name]["searh_count"] < min_find:
                main_dict.pop(company_name, None)
                continue
        if main_dict[company_name]["count"] == 0:
            main_dict[company_name]["searh_share"] = 0
        else:
            main_dict[company_name]["searh_share"] = (main_dict[company_name]["searh_count"] / main_dict[company_name]["count"] * 100)
        main_dict[company_name]["managers"] = sorted( main_dict[company_name]["managers"])
        main_dict[company_name]["searh_managers"] = sorted(main_dict[company_name]["searh_managers"])

    return main_dict


import pprint
import pandas as pd

fing_names = []
fing_names.append("ЖаровЖ.Ж.")
fing_names.append("ИволгинИ.И.")
fing_names.append("СидоровС.С.")
fing_names.append("ДятловД.Д.")
fing_names.append("КлюевК.К.")

df = pd.read_excel("sd3.xlsx", sheet_name="Лист1", header=None, skiprows=0)
info = find_managers(df.drop(0, axis="columns").iloc[:, 0:].values.tolist(), fing_names, 3, True)

pp = pprint.PrettyPrinter(width=1, compact=True)
pp.pprint(info)


Да, это более удачная реализация.
Единственно поправил, чтобы пользователь мог сам вводить состав СД для проверки:
fing_names.append(str(input("Директор-1: ")))
fing_names.append(str(input("Директор-2: ")))
fing_names.append(str(input("Директор-3: ")))
fing_names.append(str(input("Директор-4: ")))
fing_names.append(str(input("Директор-5: ")))
Все-таки при прогоне, предложенная в комменте программа выдает лишнее:
выводит совпадение при менее 50 %.

Немного переписал, используя множества python. Теперь учитываются составы CД, с 7-ю и 9-тью членами СД и выдает только общества при совпадении более 50%:
Код:
Код
import openpyxl
import pprint
wb = openpyxl.load_workbook('sd2.xlsx')
sheet=wb.get_active_sheet()

a=str(input("Директор-1: "))
b=str(input("Директор-2: "))
c=str(input("Директор-3: "))
e=str(input("Директор-4: "))
f=str(input("Директор-5: "))

test=[]
h = open('итог_по_СД.txt','w')
s2 = set()
s1 = {a,b,c,e,f}
itog=0
found=[]
for row in sheet['C3':'K38']:
    #s2={row}
    #print(s2)
    for cellObj in row:
        s2.add(cellObj.value)
        if cellObj.value ==None:
            #print(s2)
            if len(s2)==6: # если в множестве 5 чел +None
                itog=s2-s1
                if 4>len(itog)>=0:                
                    d = list(cellObj.coordinate)
                    d[0]='B'
                    dd=d[0]+d[1]                             
                    if len(d)>2:
                        dd=d[0]+d[1]+d[2]
                    i=sheet[str(dd)].value 
                    if i not in found:
                        found.append(i) 
            elif len(s2)==8: # если в множестве 7 чел +None
                itog=s2-s1            
                if 5>len(itog)>=3:
                    d = list(cellObj.coordinate)
                    d[0]='B'
                    dd=d[0]+d[1]                             
                    if len(d)>2:
                        dd=d[0]+d[1]+d[2]
                    i=sheet[str(dd)].value                    
                    if i not in found:
                        found.append(i)                    
            elif len(s2)==10: # если в множестве 9 чел +None
                itog=s2-s1 # вычитаем из 9 чел 5 чел, которые ввел пользователь
                if len(itog)==5:   #если осталось 4 чел (т.е.сопадают более 50%, то выводим имя общества)             
                    d = list(cellObj.coordinate)
                    d[0]='B'
                    dd=d[0]+d[1]                             
                    if len(d)>2:
                        dd=d[0]+d[1]+d[2]
                    i=sheet[str(dd)].value                    
                    if i not in found:
                        found.append(i)                    
                continue
     
    s2 = set()
for i in found:
    print (i)
    h.write (i+'\n')
h.close()    



Sign up to leave a comment.

Articles