2016-11-04 3 views
0

Моя цель - найти любую перестановку диагонали в матрице nxn (2 < = n < = 15). Матрица состоит из нулей и единиц.избежать вычисления всего декартова продукта (python itertools)

В настоящее время я делаю это так:

indices = [[j for j, x in enumerate(row) if x == 1] 
       for row in self.matrix] 
    cart = list(itertools.product(*indices)) 
    cart = [list(tup) for tup in cart] 
    cart = filter(lambda dia: len(list(set(dia))) == len(dia), cart) 
    return cart 

Это прекрасно работает, если матрица не слишком велика, но в остальном он терпит неудачу с: MemoryError

Так есть способ избежать целого вычисление тележки? так что, например, одна перестановка найдена, вычисление прекращается?

+0

Вы создаете несколько копий без причины. Удалите вызов списка на 'itertools.product (* index)' и 'cart = [list (tup) для tup в корзине]' также не нужно. Также фильтр будет медленнее, чем просто делать это с помощью списка comp. –

+0

Почему вы делаете 'list (itertools.product (* index))'? Вы можете легко фильтровать данные лениво. Можете ли вы добавить информацию о используемой версии Python? Python 2.x и 3.x здесь будут немного отличаться. –

+0

Я использую python 2.7. как я могу отфильтровать его лениво? Поскольку у меня есть список индексов в строке, я хочу выбрать один индекс для каждого элемента, как иначе это можно сделать без itertools.product? – ph0t3k

ответ

1

Просто сделайте все оценки ленивы, не называя list на результате itertools.product и использования itertools.ifilter вместо filter:

from itertools import ifilter, product 

indices = [[j for j, x in enumerate(row) if x == 1] for row in self.matrix] 
cart = product(*indices) 
found_cart = next(ifilter(lambda dia: len(set(dia)) == len(dia), cart), None) 

next возвращает первый случай, когда предикат ifilter является True или возвращает None в кейс нет соответствующий товар.

Расчет останавливается после того, как найден соответствующий элемент.

0

Вы можете упростить последнюю часть кода, чтобы он просто возвращает первый ответ:

def foo(matrix): 
    indices = [[j for j, x in enumerate(row) if x == 1] for row in matrix] 

    # this part is changed, very simple and efficient now 
    for dia in itertools.product(*indices): 
     if len(set(dia)) == len(dia): 
      return dia 

Другими словами, не будь такой умный с filter и лямбда, и все, что - это лишнее ,

+0

Хе-хе, да, я как бы пытаюсь использовать понимание списка и лямбда-выражения все время, но я также думаю, что его лучше читать, чем для циклов. – ph0t3k

+0

@ ph0t3k: Большинство людей найдут для меня, если в моем ответе будет намного легче читать, чем 'next (ifilter (лямбда ...'). Думайте о будущих сопровождающих вашего кода. –