2017-07-08 79 views
2

我想測試某個值是否屬於使用迭代器生成的數字序列。當然,當值確實屬於序列時,只要值滿足,就可以停止。但是當它,我想這是問題出現時。測試迭代器是否生成某個值

但是可以使用附加信息(例如,序列正在增加)。

考慮斐波那契例如:

class FibonacciIterator(object): 
    def __init__(self): 
     self.mem = [0, 1] 
    def __next__(self): 
     curr = self.mem[0] 
     new = self.mem[0]+self.mem[1] 
     self.mem[0] = self.mem[1] 
     self.mem[1] = new 
     return curr 

class Fibonacci(object): 
    def __iter__(self): 
     return FibonacciIterator() 

如果一個測試8是否屬於序列,然後一切都很好:

>>> fib = Fibonacci() 
>>> 8 in fib 
True 

但是,如果一個測試10(即不屬於然後

>>> 10 in fib 
... 

從不t erminates。但是可以通過觀察8來自13之後很容易地確定10不在序列中,並且由於序列增加,所以必然not 10 in fib

在Python中是否有一個很好的方法來實現in的這種行爲,以便10 in fib終止?

+2

可以提供__contains__'的'一個定義,知道該序列是單調遞增的。但是,對於一個生成器,'__contains__'會消耗序列,所以它可能不是特別有用。 – chepner

+0

似乎是一個問題,如果你沒有測試天氣,那麼這個數字已經超過了輸入 – VIPER

+0

@chepner的確如此:在我上面的例子中迭代器被消耗的事實並不是什麼大問題,因爲我會在其中定義'__contains__'每次使用'in'時使用'Fibonacci'類(「迭代器」)來生成一個新的'FibonacciIterator'(「迭代器」) –

回答

1

瑣碎的解決辦法是實現一個__contains__方法,只是在迭代器的副本迭代:

class FibonacciIterator(object): 
    def __init__(self): 
     self.mem = [0, 1] 

    def __iter__(self): 
     return self 

    def __contains__(self, value): 
     testit = FibonacciIterator() 
     testit.mem = list(self.mem) # copy 
     for item in testit: 
      if item == value: 
       return True 
      if item > value: 
       return False 

    def __next__(self): 
     curr = self.mem[0] 
     self.mem = self.mem[1], sum(self.mem) 
     return curr 

class Fibonacci(object): 
    def __iter__(self): 
     return FibonacciIterator() 

    def __contains__(self, value): 
     return value in iter(self) 

但是還有另一種方法來確定是否一個數是斐波那契數:如果有一個(5*n**2 + 4)(5*n**2 – 4)或兩者都是完美的正方形(整數的平方)。

我會使用的方法從this answer實現is_square功能:

def is_square(apositiveint): 
    # Source: https://stackoverflow.com/a/2489519/5393381 
    # Credit: Alex Martelli 

    x = apositiveint // 2 
    seen = {x} 
    while x * x != apositiveint: 
     x = (x + (apositiveint // x)) // 2 
     if x in seen: 
      return False 
     seen.add(x) 
    return True 

class FibonacciIterator(object): 
    def __init__(self): 
     self.mem = [0, 1] 

    def __iter__(self): 
     return self 

    def __contains__(self, value): 
     if value < self.mem[0]: 
      return False 
     else: 
      # Just check if at least one of both is a perfect square 
      value_squared_times_five = 5*value**2 
      return is_square(value_squared_times_five + 4) or is_square(value_squared_times_five - 4) 

    def __next__(self): 
     curr = self.mem[0] 
     self.mem = self.mem[1], sum(self.mem) 
     return curr 

class Fibonacci(object): 
    def __iter__(self): 
     return FibonacciIterator() 

    def __contains__(self, value): 
     return value in iter(self)