2017-07-07 82 views
0

好吧,我已经写了一个函数/方法,在这个函数/方法中,如果条件大多数时候失败,我会做一些操作,但是只有1-2次它是真的。获取python中排列的总数

这里是我的代码:

def solve_current_level(self): 
    self.remaining_possibilities = list(self.remaining_possibilities) 
    if len(self.remaining_possibilities) > 10 ** 6: 
     #self.reduce_weapon_options() 
     pass 

    guess = list(random.choice(self.remaining_possibilities)) 
    response = self.client.solve_level(self.current_level.levelNum, guess) 

    if 'roundsLeft' in response: 
     self.reset_remaining_possibilities() 
     return None 
    elif 'response' not in response: 
     return response 

    self.remaining_possibilities=[possibility for possibility in self.remaining_possibilities if game.Game_evaluate(guess, list(possibility)) == response['response']] 
    return None 

现在的问题发生时,产生非常大的排列,然后转换成一个列表,以检查是否长度超过10 ** 6然后再做些回来。这是我目前的解决方案,但问题是当它变得非常巨大的脚本被杀死。我将这段代码从ruby转换成了ruby,并且可以获得枚举器的大小而不必转换为列表,并且这个问题从来没有发生过。

这里是红宝石的代码:

def solve_current_level 
    reduce_weapon_options if @remaining_possibilities.size > 10 ** 6 
    if [email protected]_possibilities.kind_of?(Array) 
    @remaining_possibilities = @remaining_possibilities.to_a 
    end 

    guess = @remaining_possibilities.sample 
    response = @client.solve_level(@current_level.levelNum, guess) 

    if response['roundsLeft'] 
    reset_remaining_possibilities 
    return Nil 
    elsif !response['response'] 
    return response 
    end 

    @remaining_possibilities.select! do |possibility| 
    Game.evaluate(guess, possibility) == response['response'] 
    end 
    return Nil 
end 

现在您在红宝石代码看到之前它被转换为阵列/散列以继续处理计算置换的长度,并且如果所述数目大于10更大* * 6然后它调用另一个方法“reduce_weapon_options”。虽然在python中没有办法获得发生器的长度,但没有在所有事情之前转换为列表,我需要它以这种方式工作,因为此时我得到一些大尺寸的更大范围,它会被我的服务器拦截并被杀死。因为我需要使用较少的内存酷似林心如和我绝对要避免

self.remaining_possibilities =名单(self.remaining_possibilities)

在此之前蟒如果条件过去了,我不能扩展RAM /失败。

注:我使用和itertools.permutations来计算,后来被保存在“self.remaining_possibilities”

这里排列既是Python和Ruby代码:

return ([email protected]).to_a.permutation(@numGladiators) 
(THIS RETURNS AN ENUMERATOR OBJECT) 

return it.permutations(range(0, self.numWeapons), self.numGladiators) 
(THIS RETURNS A GENERATOR OBJECT) 

回答

2

以最简单的方法解决这个可能是计算所生成的排列数,使用排列式,其可以被定义为:

from math import factorial 
def nPr(n, r): 
    return int(factorial(n)/factorial(n-r)) 

然而,这要求这些数据可用,或者从创建原始排列生成器的地方开始传递长度。如果不是这种情况,因为某些原因,它可以使用itertools.tee()来从第一第二发生器,并且仅使用它计数:

def solve_current_level(self): 
    self.remaining_possibilities, perm_count = itertools.tee(self.remaining_possibilities) 
    # exhausting the 'teed' generator, leaving the 'original' intact: 
    num_perm = sum(1 for _ in perm_count) 
    if num_perm > 10 ** 6: 
     #self.reduce_weapon_options() 
     pass 
    # here we can still use self.remaining_possibilities 
    . 
    . 
    . 

既然你已经使用itertools这不是我想,这个解决方案太沉重了,但它仍然需要你浏览整个列表。尽管如此,内存占用却相当小。

+0

我有一个问题,你会看到if条件检查生成的排列的大小,当它比10更大时** 6调用另一个menthod,它排除排列并使用组合代替,所以你可以让我让知道我将如何找到可能的组合的大小,而不需要实际做“it.combinations(范围(0,self.numWeapons),self.numGladiators)”? – R0SENAM

+1

对于组合,可以使用'nCr'定义为'def nCr(n,r):return int(factorial(n)/(factorial(n-r)* factorial(r)))''而不是'nPr'。 – JohanL