2017-07-07 83 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