разбить кортеж чисел на куски - PullRequest
0 голосов
/ 08 января 2020

Допустим, у меня много видеофайлов, и я хотел бы разбить их на группы по 60 минут (было бы хорошо, если бы группировка составляла 10% после 60, но не больше). Они не должны быть равными по размеру группировками. Я предполагаю другой способ заявить об этом: я ищу наименьшее количество группировок, сумма которых <= 66. </p>

Так что идеальным примером будет:

group(59, 5, 20, 20, 1, 7, 33, 22, 20)

вернет

( (59, 1), (20, 20, 20), (5, 33, 22), (7,) )

Я не могу придумать, как это сделать, не пробуя случайные комбинации, и не вижу такого хорошего масштабирования.

Спасибо!

1 Ответ

0 голосов
/ 08 января 2020

Это дает вам комбинации элементов, общая сумма которых меньше или равна 66, отсортированных по количеству элементов (по возрастанию) и по общей сумме (по убыванию).

Работает путем создания комбинаций с использованием простого счетчик, учитывая биты его двоичного представления. Бит, установленный в единицу, означает, что элемент группы присутствует в комбинации.

Примечание: он по-прежнему проходит все возможные комбинации, но с небольшим объемом памяти. Математически говоря, это ни в коем случае не лучшее из возможных решений.

from operator import itemgetter

def combins(group, max_len=66):
    for n in range(1, 2**len(group)):
        n_bin = bin(n)[:1:-1]
        comb = tuple(l for l, c in zip(group, n_bin) if c == '1')
        s = sum(comb)
        if s <= max_len:
            yield comb, len(comb), -s

group = (59, 5, 20, 20, 1, 7, 33, 22, 20)
sorted_subs = sorted(combins(group), key=itemgetter(1, 2))
clean_subs = [c for c, _, _ in sorted_subs]
print(clean_subs)

производит

[(59,), (33,), (22,), (20,), (20,), (20,), (7,), (5,), (1,), (59, 7), (59, 5), (59, 1), (33, 22), (20, 33), (20, 33), (33, 20), (20, 22), (20, 22), (22, 20), (20, 20), (7, 33), (20, 20), (20, 20), (5, 33), (1, 33), (7, 22), (20, 7), (20, 7), (5, 22), (7, 20), (5, 20), (5, 20), (5, 20), (1, 22), (20, 1), (20, 1), (1, 20), (5, 7), (1, 7), (5, 1), (59, 5, 1), (20, 20, 22), (7, 33, 22), (20, 22, 20), (20, 22, 20), (20, 7, 33), (20, 7, 33), (5, 33, 22), (20, 20, 20), (7, 33, 20), (5, 20, 33), (5, 20, 33), (5, 33, 20), (1, 33, 22), (20, 1, 33), (20, 1, 33), (1, 33, 20), (20, 7, 22), (20, 7, 22), (7, 22, 20), (20, 20, 7), (5, 20, 22), (5, 20, 22), (20, 7, 20), (20, 7, 20), (5, 22, 20), (5, 20, 20), (5, 7, 33), (5, 20, 20), (5, 20, 20), (20, 1, 22), (20, 1, 22), (1, 22, 20), (20, 20, 1), (1, 7, 33), (20, 1, 20), (20, 1, 20), (5, 1, 33), (5, 7, 22), (5, 20, 7), (5, 20, 7), (5, 7, 20), (1, 7, 22), (20, 1, 7), (20, 1, 7), (5, 1, 22), (1, 7, 20), (5, 20, 1), (5, 20, 1), (5, 1, 20), (5, 1, 7), (5, 20, 7, 33), (5, 20, 7, 33), (5, 20, 20, 20), (5, 7, 33, 20), (20, 20, 1, 22), (1, 7, 33, 22), (20, 1, 22, 20), (20, 1, 22, 20), (20, 1, 7, 33), (20, 1, 7, 33), (5, 1, 33, 22), (20, 20, 1, 20), (1, 7, 33, 20), (5, 20, 1, 33), (5, 20, 1, 33), (5, 1, 33, 20), (5, 20, 7, 22), (5, 20, 7, 22), (5, 7, 22, 20), (5, 20, 20, 7), (5, 20, 7, 20), (5, 20, 7, 20), (20, 1, 7, 22), (20, 1, 7, 22), (1, 7, 22, 20), (20, 20, 1, 7), (5, 20, 1, 22), (5, 20, 1, 22), (20, 1, 7, 20), (20, 1, 7, 20), (5, 1, 22, 20), (5, 20, 20, 1), (5, 1, 7, 33), (5, 20, 1, 20), (5, 20, 1, 20), (5, 1, 7, 22), (5, 20, 1, 7), (5, 20, 1, 7), (5, 1, 7, 20), (5, 20, 1, 7, 33), (5, 20, 1, 7, 33), (5, 20, 20, 1, 20), (5, 1, 7, 33, 20), (5, 20, 1, 7, 22), (5, 20, 1, 7, 22), (5, 1, 7, 22, 20), (5, 20, 20, 1, 7), (5, 20, 1, 7, 20), (5, 20, 1, 7, 20)]

Если вы хотите получить наилучшее соответствие для любого заданного размера, результаты можно сгруппировать по размер

from collections import defaultdict
from pprint import pprint

combs_by_size = defaultdict(list)
for comb, size, _ in sorted(combins(group), key=itemgetter(1, 2)):
    combs_by_size[size].append(comb)
pprint(combs_by_size)

, который производит

defaultdict(<class 'list'>,
            {1: [(59,), (33,), (22,), (20,), (20,), (20,), (7,), (5,), (1,)],
             2: [(59, 7),
                 (59, 5),
                 (59, 1),
                 (33, 22),
                 (20, 33),
                 (20, 33),
                 (33, 20),
                 (20, 22),
                 (20, 22),
                 (22, 20),
                 (20, 20),
                 (7, 33),
                 (20, 20),
                 (20, 20),
                 (5, 33),
                 (1, 33),
                 (7, 22),
                 (20, 7),
                 (20, 7),
                 (5, 22),
                 (7, 20),
                 (5, 20),
                 (5, 20),
                 (5, 20),
                 (1, 22),
                 (20, 1),
                 (20, 1),
                 (1, 20),
                 (5, 7),
                 (1, 7),
                 (5, 1)],
             3: [(59, 5, 1),
                 (20, 20, 22),
                 (7, 33, 22),
                 (20, 22, 20),
                 (20, 22, 20),
                 (20, 7, 33),
                 (20, 7, 33),
                 (5, 33, 22),
                 (20, 20, 20),
                 (7, 33, 20),
                 (5, 20, 33),
                 (5, 20, 33),
                 (5, 33, 20),
                 (1, 33, 22),
                 (20, 1, 33),
                 (20, 1, 33),
                 (1, 33, 20),
                 (20, 7, 22),
                 (20, 7, 22),
                 (7, 22, 20),
                 (20, 20, 7),
                 (5, 20, 22),
                 (5, 20, 22),
                 (20, 7, 20),
                 (20, 7, 20),
                 (5, 22, 20),
                 (5, 20, 20),
                 (5, 7, 33),
                 (5, 20, 20),
                 (5, 20, 20),
                 (20, 1, 22),
                 (20, 1, 22),
                 (1, 22, 20),
                 (20, 20, 1),
                 (1, 7, 33),
                 (20, 1, 20),
                 (20, 1, 20),
                 (5, 1, 33),
                 (5, 7, 22),
                 (5, 20, 7),
                 (5, 20, 7),
                 (5, 7, 20),
                 (1, 7, 22),
                 (20, 1, 7),
                 (20, 1, 7),
                 (5, 1, 22),
                 (1, 7, 20),
                 (5, 20, 1),
                 (5, 20, 1),
                 (5, 1, 20),
                 (5, 1, 7)],
             4: [(5, 20, 7, 33),
                 (5, 20, 7, 33),
                 (5, 20, 20, 20),
                 (5, 7, 33, 20),
                 (20, 20, 1, 22),
                 (1, 7, 33, 22),
                 (20, 1, 22, 20),
                 (20, 1, 22, 20),
                 (20, 1, 7, 33),
                 (20, 1, 7, 33),
                 (5, 1, 33, 22),
                 (20, 20, 1, 20),
                 (1, 7, 33, 20),
                 (5, 20, 1, 33),
                 (5, 20, 1, 33),
                 (5, 1, 33, 20),
                 (5, 20, 7, 22),
                 (5, 20, 7, 22),
                 (5, 7, 22, 20),
                 (5, 20, 20, 7),
                 (5, 20, 7, 20),
                 (5, 20, 7, 20),
                 (20, 1, 7, 22),
                 (20, 1, 7, 22),
                 (1, 7, 22, 20),
                 (20, 20, 1, 7),
                 (5, 20, 1, 22),
                 (5, 20, 1, 22),
                 (20, 1, 7, 20),
                 (20, 1, 7, 20),
                 (5, 1, 22, 20),
                 (5, 20, 20, 1),
                 (5, 1, 7, 33),
                 (5, 20, 1, 20),
                 (5, 20, 1, 20),
                 (5, 1, 7, 22),
                 (5, 20, 1, 7),
                 (5, 20, 1, 7),
                 (5, 1, 7, 20)],
             5: [(5, 20, 1, 7, 33),
                 (5, 20, 1, 7, 33),
                 (5, 20, 20, 1, 20),
                 (5, 1, 7, 33, 20),
                 (5, 20, 1, 7, 22),
                 (5, 20, 1, 7, 22),
                 (5, 1, 7, 22, 20),
                 (5, 20, 20, 1, 7),
                 (5, 20, 1, 7, 20),
                 (5, 20, 1, 7, 20)]})

Таким образом, получение первого элемента списка заданного размера дает вам наилучшее соответствие для такого размера, например

print(combs_by_size[3][0])

дает

(59, 5, 1)

Как вы могли заметить, выходные комбинации показывают значения только в том виде, в каком они есть, поэтому элементы группы нельзя отличить друг от друга, если они имеют одно и то же значение, например, число 20 кажется кратным раз в выборочной группе. Чтобы узнать, что это за 20, нам нужно добавить атрибут рядом со значением, возможно, в виде кортежа (filename, length) вместо length только как сейчас.

...