2012-06-12 14 views
7

tworzę listę z itertools z listy zakresów, tak dalece mam to:Python tworzy listę za pomocą itertools.product?

start_list = [xrange(0,201,1),xrange(0,201,2),xrange(0,201,5),xrange(0,201,10),xrange(0,201,20),xrange(0,201,50),xrange(0,201,100),xrange(0,201,200)] 

Teraz wiem, że gdybym spróbować uruchomić ten następny wiersz będzie zabić mojego interpretera Pythona :

next_list = list(itertools.product(*start_list)) 

Co Zastanawiam się byłoby możliwe do wprowadzenia w argument, który sprawdza każda krotka, bo suma jego elementów i tylko umieszcza je w next_list jeśli równa określonej kwoty?

Może coś takiego:

next_list = list(itertools.product(*start_list,sum(tuples)=200)) 

wiem, że to nie jest w porządku, a może muszę zacząć ponownie myśleć drogę Idę na ten temat. Czy zakresy start_list w generatorze będą zbyt duże, aby można było zbudować kolejną listę?

+4

Jeśli próbujesz dowiedzieć się, jak podzielić partycję 200 na 8 terminów z różnych zestawów, istnieją łatwiejsze sposoby obliczania następnej listy. Jeśli się liczę, twój produkt kartezjański ma 5768123130 odrębnych elementów do iteracji, co zajmie sporo czasu. – DSM

+0

Witaj DSM, dziękuję za odpowiedź. Zajmę się tworzeniem bardziej wydajnej metody. – tijko

+0

powiązane: http://stackoverflow.com/questions/1106929/find-all-combinations-of-coins-when-given-some-dollar-value – jfs

Odpowiedz

12

lepiej po prostu skorzystać z listy rozumienie

new_list = [item for item in itertools.product(*start_list) if sum(item) == 200] 
+0

Twoje rozwiązanie sprawia, że ​​intencje są znacznie wyraźniejsze. –

+0

Hej gnibbler, dzięki za odpowiedź. Próbowałem tego 'for i in list (itertools.product (* start_list)): if sum (i) == 200: new_list.append (i)' Który także rozbił interpreter. Teraz, mimo że muszę znaleźć inny sposób rozwiązania tego problemu, nauczyłem się dzięki komentarzowi! – tijko

1

Użyj tego:

next_list = list (pozycja dla elementu w itertools.product (* START_LIST) jeżeli suma (poz) == 200)

+0

@gnibbler: Myślę, że źle odczytałeś nazwę zmiennej;) –

+0

No pewnie, jestem tym, który nie wypił wystarczającej ilości kawy –

+0

@gnibbler: Sam jestem na 12. pitrze. Wyłączone dla ostryg i wina :) –

2
Solution  Runtime   Fn calls   Lines of Code 
-------- ---------- ------------------------ ------------- 
gnibbler 2942.627 s 1473155845 (1.5 billion)   1 
me_A   16.639 s  28770812 (29 million)   5 
me_B   0.452 s  774005 (.8 million)   43 

Rozwiązanie me_A:

import itertools 

def good_combos(basis, addto): 
    good_sums = set(addto-b for b in basis[0]) 
    return ([addto-sum(items)]+list(items) for items in itertools.product(*basis[1:]) if sum(items) in good_sums) 

next_list = list(good_combos(start_list, 200)) 

Należy pamiętać, że może to być znacznie szybciej jeśli przejdą mu najdłuższy pierwszy listę.

To rozwiązanie zastępuje jeden poziom iteracji zestawem wyszukiwania; z najdłuższą listą zawierającą 200 pozycji, nie powinno dziwić, że jest to prawie 200 razy szybsze.


Rozwiązanie me_B:

import itertools 
from bisect import bisect_left, bisect_right 

def good_combos(addto=0, *args): 
    """ 
    Generate all combinations of items from a list of lists, 
    taking one item from each list, such that sum(items) == addto. 

    Items will only be used if they are in 0..addto 

    For speed, try to arrange the lists in ascending order by length. 
    """ 
    if len(args) == 0:       # no lists passed? 
     return [] 

    args = [sorted(set(arg)) for arg in args] # remove duplicate items and sort lists in ascending order 
    args = do_min_max(args, addto)    # use minmax checking to further cull lists 

    if any(len(arg)==0 for arg in args):  # at least one list no longer has any valid items? 
     return [] 

    lastarg = set(args[-1]) 
    return gen_good_combos(args, lastarg, addto) 

def do_min_max(args, addto, no_negatives=True): 
    """ 
    Given 
     args   a list of sorted lists of integers 
     addto   target value to be found as the sum of one item from each list 
     no_negatives if True, restrict values to 0..addto 

    Successively apply min/max analysis to prune the possible values in each list 

    Returns the reduced lists 
    """ 
    minsum = sum(arg[0] for arg in args) 
    maxsum = sum(arg[-1] for arg in args) 

    dirty = True 
    while dirty: 
     dirty = False 
     for i,arg in enumerate(args): 
      # find lowest allowable value for this arg 
      minval = addto - maxsum + arg[-1] 
      if no_negatives and minval < 0: minval = 0 
      oldmin = arg[0] 
      # find highest allowable value for this arg 
      maxval = addto - minsum + arg[0] 
      if no_negatives and maxval > addto: maxval = addto 
      oldmax = arg[-1] 

      if minval > oldmin or maxval < oldmax: 
       # prune the arg 
       args[i] = arg = arg[bisect_left(arg,minval):bisect_right(arg,maxval)] 
       minsum += arg[0] - oldmin 
       maxsum += arg[-1] - oldmax 
       dirty = True 
    return args 

def gen_good_combos(args, lastarg, addto): 
    if len(args) > 1: 
     vals,args = args[0],args[1:] 
     minval = addto - sum(arg[-1] for arg in args) 
     maxval = addto - sum(arg[0] for arg in args) 
     for v in vals[bisect_left(vals,minval):bisect_right(vals,maxval)]: 
      for post in gen_good_combos(args, lastarg, addto-v): 
       yield [v]+post 
    else: 
     if addto in lastarg: 
      yield [addto] 

basis = reversed(start_list) # more efficient to put longer params at end 
new_list = list(good_combos(200, *basis)) 

do_min_max() naprawdę nie można niczego osiągnąć na zbiorze danych - każda lista zawiera zarówno 0 i addto, pozbawiając go wszelkich dźwigni - jednak na podstawie bardziej ogólnych dane mogą znacznie zmniejszyć rozmiar problemu.

Oszczędności w tym zakresie wynikają z sukcesywnego zmniejszania liczby przedmiotów rozpatrywanych na każdym poziomie iteracji (przycinanie drzew).

+0

Jeśli twojemu kodowi zajęło 50 minut, to nadal bym wygrywał :). Poważnie, moja odpowiedź dotyczyła tylko pierwotnego problemu, a nie reguły 1-minutowej –

+1

@gnibbler: bardziej jak 3 godziny zabawy z długą wersją, zanim pojawiła się moja krótka wersja. –

+0

Oba bardzo pomocne, będę się uczyć od obu: D – tijko

Powiązane problemy