Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/21: Рейтинг темы: голосов - 21, средняя оценка - 5.00
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134

Как ускорить работу скрипта по перебору, комбинации сумм

14.05.2021, 10:55. Показов 4514. Ответов 33

Студворк — интернет-сервис помощи студентам
Ребята, добрый день!

Есть такая проблема не могу решить.
Дано, файл Excel c 10 000 тыс.(может быть и больше) записей, эти данные я
загружаю в словарь Python, далее из этих данных хочу получить желаемую сумму. Но скрипт работает очень долго,
т.к. много вариантов перебора, может работать годами , как переписать код чтобы получить только одну запись и выйти из цикла, плюс значение комбинации записать в файл.
Пример:
'13098194': 5413033.09, '14024911': 4799851.78, 12794945': 3606633.61 что в итоге дает желаемую сумму: 138195,18


Пример словаря:
Python
1
2
3
4
5
6
7
8
9
10
11
resultdict = {
         '13098194': 5413033.09,
         '14024911': 4799851.78,
         '15478940': 4274028,
         '12794945': 3606633.61,
         '16124010': 3083362.91,
         '17045813': 2914115.9,
         '17355657': 2873580.38,
         '17194240': 2817811.2
....
}
Делаю так:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# -*- coding: utf8 -*-
import itertools, time
from openpyxl import load_workbook
 
start_time = time.time() #Время запуска скрипта
 
wb = load_workbook('Тест.xlsx') #
sheet_ranges = wb['Sheet1']
 
total = float(sheet_ranges['E1'].value)
 
temp1 = {} #Временный словарь для загрузки данных
resultdict = {} #Словарь без дублей и сортировкой
 
for row in sheet_ranges.iter_rows():
    if row[0].value is not None and row[1].value is not None and row[1].value <= total:
        column_A = str(row[0].value)
        column_B = row[1].value
        temp1[column_A] = column_B  #Заполняем словарь данными из Excel.
temp2 = {}
[temp2.update({k:v}) for k,v in temp1.items() if v not in temp2.values()]
 
#Сортировка от большего к меньшему, если total > 1 000 000
if int(total) > 1000000:
    for i in sorted(temp2.items(),reverse=True, key=lambda para: para[1]):
        resultdict[i[0]]=i[1]
#Сортировка от меньшего к большему, если total < 1 000 000
elif int(total) < 1000000:
    for i in sorted(temp2.items(),reverse=False, key=lambda para: para[1]):
        resultdict[i[0]]=i[1]
 
# for key, value in resultdict.items():
#     print(key, value)
 
for r in range(1, len(resultdict) + 1):
    for keys_combination in itertools.combinations(resultdict, r):
        if sum([resultdict[key] for key in keys_combination]) == total:
            with open("result.txt", "w") as f:
                f.write({key: resultdict[key] for key in keys_combination},file=f)
 
 
print()
print('Желаемая сумма:',total)
print('Количество строк из файла Excel:',len(temp1))
print('Количество строк без дублей и сортировкой:',len(resultdict))
 
 
 
 
 
end_time = time.time() #Время окончания работы скрипта
print()
print(f"На вычисление потребовалось {end_time-start_time:.2f} секунд")
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.05.2021, 10:55
Ответы с готовыми решениями:

Как ускорить работу скрипта в таблицах Google?
Есть таблица, в которой много листов. Часть ячеек заполнена значениями, часть — формулами. Требуется заблокировать ячейки с формулами от...

ускорить работу скрипта
Друзья - php скрипт выполняется более 400 секунд! Подскажите что можно подправить - что бы ускорить работу! &lt;?php $dbh =...

Как можно связать работу скрипта из балуна с работой скрипта на странице?
Первый раз задаю вопрос, извините если не в тот раздел. В общем, делаю метку через Яндекс карты и в балунКонтент записываю кнопку с...

33
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 10:59
Цитата Сообщение от Exle Посмотреть сообщение
что в итоге дает желаемую сумму: 138195,18
каким образом? первое число уже больше этой "суммы"

если в ячейках уже есть значение с нужным числом то оно то же является решением? или всегда должна быть сумма 3? если сумма 2 будет искомым - сойдет?
0
3582 / 2182 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
14.05.2021, 11:02
Exle, кури: Subset Sum Problem | DP-25.
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 11:29  [ТС]
С суммами накосячил, пример:
Желаемая сумма скажем 10000:
'121212': 5000,
'1211232': 4000,
'12367': 1000
0
Эксперт Python
8851 / 4502 / 1864
Регистрация: 27.03.2020
Сообщений: 7,317
14.05.2021, 12:02
Exle,
файл Excel c 10 000 тыс.(может быть и больше) записей
Вариантов различных сумм до 2^10 000 ~ 10^3000
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 12:04
Exle, а остальные вопросы?
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 12:23  [ТС]
if (sum == 0):
RecursionError: maximum recursion depth exceeded in comparison

Добавлено через 10 минут
если в ячейках уже есть значение с нужным числом то оно то же является решением? или всегда должна быть сумма 3? если сумма 2 будет искомым - сойдет?

По идеи если число есть в словаре то его можно считать за решение, вариант решений:
Желаемая сумма: 3
Результат: '434434': 2, '78787': 1

Желаемая сумма: 4
Результат: '123456': 4,

Желаемая сумма: 7
Результат: '343435': 6, '78787': 1, (вывести только первый встретившийся)
Хотя может быть еще:
'434434': 2, '78187': 5,
Если есть хоть один результат, перерывать перебор.


Получаем:
т.е.
'123456': 4,
'343435': 6,
'434434': 2,
'78787': 1,
'78187': 5,
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 12:35
сумма больше чем 3 ячеек может быть?
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 12:45  [ТС]
да все варианты, (не ограниченно) и если первое совпадение есть цикл обрывался, чтобы время не тратить

главное чтобы сумма добиралась из значений ячейки, у меня это работает только долго(бесконечно с таким количеством записей ) и не смог реализовать первый попавшийся вариант
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 13:33
Exle, файл то приложи на 10000 строк данных, можно в выходные попробовать, может и еще кто присоединится. Вроде не должно быть долго, да и break никто не отменял
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 13:38  [ТС]
а как понять что в переменной есть значение, проверить это?
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 13:40
однако!
присвоить ей в начале 0 или нан и потом проверить все еще там 0/нан или нет.
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 13:45  [ТС]
Добавил.
Вложения
Тип файла: xlsx Тестирование.xlsx (232.6 Кб, 6 просмотров)
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 13:51  [ТС]
Эту переменную все равно долго ждать по времени, даже если брейк сделать.
0
Эксперт Python
8851 / 4502 / 1864
Регистрация: 27.03.2020
Сообщений: 7,317
14.05.2021, 15:26
Exle, посмотри на numpy. Если оперативки хватит, то относительно быстро находит. В коде поиск среди всех сумм по три элемента. Можно увеличить, но там нужно "мудрить" с индексами, иначе "выбросит по памяти"
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
n = 500 # количество элементов
find_sum = 1495. # требуемая сумма
a = np.array(list(range(n)), dtype=float) # входной массив 
print(a)
np.random.shuffle(a)
print(a)
c = np.add.outer(a,a)
i, j = np.where(c==find_sum)
for k in zip(i,j):
    print(k, c[k])
 
##### если i, j "пустые", то
c[np.tril_indices(n)] = np.nan
c[c>find_sum] = np.nan
c = np.add.outer(c,a)
i, j, m = np.where(c==find_sum)
for k in zip(i,j,m):
    print(k, c[k])
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
14.05.2021, 16:03  [ТС]
Я слышал, что элементы "numpy" должны быть одного типа, а у меня значения int, float

Добавлено через 10 минут
с 3-я эл. если задать значение кол-во символов 10000, падает по памяти.
numpy.core._exceptions.MemoryError: Unable to allocate 7.28 TiB for an array with shape (10000, 10000, 10000) and data type float64
0
Эксперт Python
8851 / 4502 / 1864
Регистрация: 27.03.2020
Сообщений: 7,317
14.05.2021, 16:22
Exle, об этом и писал - для 10000 элементов все комбинации сумм по три элемента равно ~ 1 трл / 2
1. Можно убрать элементы больше требуемой суммы
2. Потом в сумме по двум убрать все суммы больше искомой, запоминая индексы оставшихся сумм в другом массиве (получится список списков)
3. Разворачивание массива сумм в линейный массив
4. Создание нового массива сумм
5. Повтор 1.
6. Повтор 2. Но тут при запоминании индекса убираем подсписки с одинаковыми индексами (число из исходного массива должно один раз суммироваться)
И тд
Но все равно без существенных доп ограничений при 10000 элементах задача очень затратная по памяти
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
14.05.2021, 17:59
Добавлено через 5 минут
Exle, вот так навскидку, решение плохое, если искать большую сумму (но меньше суммы всех ячеек) которой точно нет, то занимает минуту, плюс все храню в памяти, проверяю не более суммы 3 ячеек и флоаты округляю до 2 знаков для сравнения. Но может тебе хватит

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from bisect import bisect_left
from operator import itemgetter
from typing import Dict, List
from time import time
 
from openpyxl import load_workbook
 
 
def get_data(file_name: str) -> Dict[str, float]:
    work_book = load_workbook(file_name)
    sheet = work_book['Sheet1']
    pairs = {row[0].value: float(row[1].value) for row in sheet.iter_rows() if row[0].value and row[1].value}
    return dict(sorted(pairs.items(), key=itemgetter(1)))
 
 
def calculate(pairs: Dict[str, float], value: float) -> List[str]:
    sorted_pairs = list(pairs.items())
    min_ = sorted_pairs[0][1]
    sum_ = round(sum(pairs.values()), 2)
    if value < min_:
        raise ValueError(f'Значение {value} меньше минимального значения в таблице({min_})!')
    if value > sum_:
        raise ValueError(f'Значение {value} больше суммы всех значений в таблице({sum_})!')
    if value == sum_:
        print(f'Нужное число({value}) это сумма всех ячеек!')
        return list(pairs.keys())
    sorted_values = list(pairs.values())
    index_ = index(sorted_values, value)
    if index_ is not None:
        return [sorted_pairs[index_][0]]
    pair = _find_sum_of_two(value, sorted_values)
    if pair:
        return [sorted_pairs[pair[0]][0], sorted_pairs[pair[1]][0]]
    triple = _find_sum_of_three(value, sorted_values)
    if triple:
        return [sorted_pairs[triple[0]][0], sorted_pairs[triple[1]][0], sorted_pairs[triple[2]][0]]
    return []
 
 
def _find_sum_of_three(value, sorted_values):
    for initial_value in sorted((e for e in sorted_values if e < value), reverse=True):
        to_find = round(value - initial_value, 2)
        pairs = _find_sum_of_two(to_find, sorted_values)
        if pairs:
            return index(sorted_values, initial_value), *pairs
    return tuple()
 
 
def _find_sum_of_two(value, sorted_values: List[float]) -> tuple:
    for initial_value in sorted((e for e in sorted_values if e < value), reverse=True):
        to_find = round(value - initial_value, 2)
        index_ = index(sorted_values, to_find)
        if index_ is not None:
            return index(sorted_values, initial_value), index_
    return tuple()
 
 
def index(a, x):
    i = bisect_left(a, x)
    if i != len(a) and a[i] == x:
        return i
    return None
 
 
if __name__ == '__main__':
    pairs = get_data('Тестирование.xlsx')
    start = time()
    print(calculate(pairs, 81810.91))  # ['16579079', '15473880', '15634093']
    print(calculate(pairs, 51502.48))  # ['11550029', '11550031']
    print(calculate(pairs, 1163258.98))  # ['16278978']
    print(f'Time elapsed: {time() - start}')
0
2 / 2 / 1
Регистрация: 13.09.2019
Сообщений: 134
17.05.2021, 09:09  [ТС]
Суть в том чтобы находить все возможные комбинации сумм, которая в итоге дает желаемое число.
Как писал, ранее их может быть одна, две, а может и десять. Но выводить одну первое совпадение, чтобы время не тратить.

Добавлено через 29 минут
Попробуйте для теста число, 116 267 835.30 Это комбинация ячеек СУММ(B1:B44)
Итог: (пусто)
[]
Time elapsed: 79.10106086730957
0
Автоматизируй это!
Эксперт Python
 Аватар для Welemir1
7392 / 4819 / 1246
Регистрация: 30.03.2015
Сообщений: 13,694
Записей в блоге: 29
17.05.2021, 18:14
Цитата Сообщение от Exle Посмотреть сообщение
Попробуйте для теста число
я кажется уже написал что проверяются только комбинашки 2 и 3 ячеек)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.05.2021, 18:14
Помогаю со студенческими работами здесь

Как ускорить быстродействие скрипта [многопоточность]
Всем привет. задумал написать некий демон на perl. Его задача: в бесконечном цикле выбирать записи из б.д. mysql , после чего выполнять по...

Как ускорить работу IJ?
Ребят, всем добрый день, я читал, что ява компилируется дольше, чем си, но у меня как-то долго... дайте пару советов, как ускорить работу:p

Как ускорить работу?
Прога ещё не доработана, сейчас интересует именно графический режим, когда нажимается клавиша 1-4 один из 4-х квадратов должен...

Как ускорить работу
Всем доброго дня! У меня существует таблица на 50 000 строк СУБД Mysql, в одной части таблицы 200 строк имеется запись &quot;-&quot;, в...

Как ускорить работу программы
Доброго времени суток! Разработал первую программу для logo! на FBD. На симуляторе все нормально. После установки на оборудование...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru