简体   繁体   English

获取python中排列的总数

[英]Get the total number of permutations in python

Okay i have written a function/method in which I do some operations after a certain if condition is failed mostly but only 1-2 times it will be true. 好的,我编写了一个函数/方法,在确定条件是否大多数失败之后,我可以进行一些操作,但是只有1-2次是正确的。

Here is my code: 这是我的代码:

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

Now the problem happens when very large permutations is generated and then converted into a list to check if the length is over 10**6 then do something else and come back. 现在,当生成非常大的排列然后将其转换为列表以检查长度是否超过10 ** 6时,就会发生问题,然后执行其他操作并返回。 This is my current solution but issue is when it gets very huge script gets killed. 这是我当前的解决方案,但问题是,当脚本变得非常庞大时,该脚本被杀死。 I converted this piece of code from ruby and in ruby one can get the size of enumerator without converting to list as well and this issue never happens there. 我从ruby转换了这段代码,在ruby中可以得到枚举器的大小而无需转换为list,并且这个问题永远不会发生。

Here is the code in ruby: 这是ruby中的代码:

def solve_current_level
  reduce_weapon_options if @remaining_possibilities.size > 10 ** 6
  if !@remaining_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

Now you see in ruby code the length of permutations is calculated before it is converted to array/hash to continue processing and if the number is bigger than 10**6 then it calls another method "reduce_weapon_options". 现在,您可以在ruby代码中看到排列的长度,然后将其计算为数组/哈希值以继续处理,如果该数目大于10 ** 6,则它将调用另一个方法“ reduce_weapon_options”。 While in python there is not way to get the length of generator without converting to list before everything, I need it to work that way as at this moment when i get some bigger range with big size, it stucks and gets killed by my server. 虽然在python中没有办法获得生成器的长度而不转换成列表,但我需要它以这种方式工作,因为这时我获得了更大的更大范围,它被卡住并被我的服务器杀死。 I cannot extend ram as I need to use less ram exactly like ruby and i absolutely want to avoid 我无法扩展ram,因为我需要像ruby一样少使用ram,我绝对希望避免

self.remaining_possibilities = list(self.remaining_possibilities) self.remaining_possibilities =列表(self.remaining_possibilities)

this in python before if condition is passed/failed. 如果条件通过/失败,则在python中执行此操作。

NOTE: I am using itertools.permutations to calculate permutations that later gets saved in "self.remaining_possibilities" 注意:我正在使用itertools.permutations来计算后来保存在“ self.remaining_possibilities”中的排列

Here is that code both in python and ruby: 这是python和ruby中的代码:

return (0...@numWeapons).to_a.permutation(@numGladiators)
(THIS RETURNS AN ENUMERATOR OBJECT)

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

The simplest way to solve this is probably to calculate the number of permutations generated, using the permutations formula, which can be defined as: 解决此问题的最简单方法可能是使用排列公式来计算生成的排列数量,可以将其定义为:

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

This, however, requires that this data is available or that the length is passed along from the place where the original permutations generator was created. 但是,这要求此数据可用,或者从创建原始排列生成器的位置开始传递长度。 If this is not the case, for some reason, it is possible to use itertools.tee() to generate a second generator from the first, and use it only for counting: 如果不是这种情况,出于某种原因,可以使用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
    .
    .
    .

Since you are already using itertools this is not a too heavy solution, I guess, but it still requires you to go through the whole list. 我想,既然您已经在使用itertools这并不是一个很繁重的解决方案,但仍然需要您仔细阅读整个列表。 The memory footprint is considerably smaller, though. 但是,内存占用空间要小得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM