获取python中的排列总数

时间:2017-07-07 18:11:00

标签: python rubygems

好的,我已经编写了一个函数/方法,在这个函数/方法之后我会在一定条件下执行一些操作,但是大多数条件都会失败,但只有1-2次才会成真。

这是我的代码:

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中可以获得枚举器的大小而不转换为列表,这个问题永远不会发生在那里。

以下是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

现在您在ruby代码中看到排列的长度在转换为数组/哈希以继续处理之前计算,如果数字大于10 ** 6则会调用另一个方法“reduce_weapon_options”。虽然在python中没有办法获得生成器的长度而没有转换到列表之前的所有内容,我需要它以这种方式工作,因为此时我得到一个更大的范围与大尺寸,它卡住并被我的服务器杀死。我无法扩展ram,因为我需要使用更少的ram,就像ruby一样,我绝对想避免

  

self.remaining_possibilities = list(self.remaining_possibilities)

如果条件通过/失败,则在python中执行此操作。

注意:我使用itertools.permutations来计算后来保存在“self.remaining_possibilities”中的排列

以下是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)

1 个答案:

答案 0 :(得分: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,因此我认为这不是一个太重的解决方案,但它仍然需要您浏览整个列表。但是,内存占用量要小得多。