M.Hiroi's Home Page
http://www.geocities.jp/m_hiroi/

お気楽 Ruby プログラミング入門

付録

[ PrevPage | R u b y | NextPage ]

Enumerator

irb> class Foo
irb> def each
irb> yield 1
irb> yield 2
irb> yield 3
irb> end
irb> end
=> :each
irb> a = Foo.new
=> #<Foo: ... >
irb> a.map {|x| x * x}
NoMethodError: undefined method `map' for #<Foo: ... >
・・・省略・・・

irb> e = a.to_enum
=> #<Enumerator: #<Foo: ... >:each>
irb> e.map {|x| x * x}
=> [1, 4, 9]
irb> e.next
=> 1
irb> e.next
=> 2
irb> e.next
=> 3
irb> e.next
StopIteration: iteration reached an end

irb> e.rewind
=> #<Enumerator: #<Foo: ... >:each>
irb> e.peek
=> 1
irb> e.peek
=> 1
irb> e.peek_values
=> [1]
irb> e.next_values
=> [1]
irb> e.next_values
=> [2]
irb> [1,2,3,4,5].to_enum.with_index{|k, i| print i, " ", k, "\n"}
0 1
1 2
2 3
3 4
4 5
=> [1, 2, 3, 4, 5]
irb> [1,2,3,4,5].to_enum.with_index(1){|k, i| print i, " ", k, "\n"} 
1 1
2 2
3 3
4 4
5 5
=> [1, 2, 3, 4, 5]
irb> [1,2,3,4,5].each_with_index{|k, i| print i, " ", k, "\n"}
0 1
1 2
2 3
3 4
4 5
=> [1, 2, 3, 4, 5]
irb> ints = Enumerator.new(Float::INFINITY) {|y|
irb> n = 1
irb> loop {
irb> y << n
irb> n += 1
irb> }
irb> }
=> #<Enumerator: #<Enumerator::Generator: ... >:each>
irb> ints.next
=> 1
irb> ints.next
=> 2
irb> ints.next
=> 3
irb> ints.next
=> 4
irb> ints.next
=> 5
irb> ints.rewind
=> #<Enumerator: #<Enumerator::Generator: ... >:each>
irb> ints.next
=> 1
irb> ints.next
=> 2
irb> ints.next
=> 3
irb> ints.size
=> Infinity

●参考 URL


Enumerator::Lazy

irb> intslazy = ints.lazy
=> #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator: ... >:each>>
irb> intslazy.next
=> 1
irb> intslazy.next
=> 2
irb> intslazy.next
=> 3
irb> intslazy.drop(100)
=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator: ... >:each>>:drop(100)>
irb> intslazy.drop(100).first
=> 101
irb> intslazy.drop(100).first(10)
=> [101, 102, 103, 104, 105, 106, 107, 108, 109, 110]
irb> intslazy.map {|x| x * 2}
=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator: ... >:each>>:map>
irb> intslazy.map {|x| x * 2}.take(10).force
=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
irb> intslazy.map {|x| x * 2}.first(10)
=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

●簡単な例題

リスト : 無限数列の生成

def iterate(a, &func)
  Enumerator.new(Float::INFINITY) {|y|
    n = a
    loop {
      y << n
      n = func.call(n)
    }
  }.lazy
end

def tabulate(a = 0, &func)
  Enumerator.new(Float::INFINITY) {|y|
    n = a
    loop {
      y << func.call(n)
      n += 1
    }
  }.lazy
end
irb> iterate(1, &:itself).first(10)
=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
irb> iterate(2, &:itself).first(10)
=> [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
irb> iterate(1){|x| x + 1}.first(10)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb> iterate(1){|x| x + 2}.first(10)
=> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
irb> iterate([0, 1]){|x, y| [y, y + x]}.first(10)
=> [[0, 1], [1, 1], [1, 2], [2, 3], [3, 5], [5, 8], [8, 13], [13, 21], [21, 34], [34, 55]]
irb> iterate([0, 1]){|x, y| [y, y + x]}.map{|x| x[0]}.first(10)    # フィボナッチ数
=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
irb> iterate([2, 1]){|x, y| [y, y + x]}.map{|x| x[0]}.first(10)    # リュカ数
=> [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
irb> iterate([0, 0, 1]){|x, y, z| [y, z, z + y + x]}.map{|x| x[0]}.first(20)  # トリボナッチ数
=> [0, 0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513]

irb> tabulate(&:itself).first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb> tabulate(10, &:itself).first(10)
=> [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
irb> tabulate(1){|x| x * (x + 1) / 2}.first(10)     # 三角数
=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
irb> tabulate(1){|x| x * x}.first(10)               # 四角数
=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
irb> tabulate(1){|x| x * (3 * x - 1) / 2}.first(10) # 五角数
=> [1, 5, 12, 22, 35, 51, 70, 92, 117, 145]

irb> def to_fizzbuzz(n)
irb> if n % 15 == 0
irb> "FizzBuzz"
irb> elsif n % 3 == 0
irb> "Fizz"
irb> elsif n % 5 == 0
irb> "Buzz"
irb> else
irb> n.to_s
irb> end
irb> end
=> :to_fizzbuzz
irb> tabulate(1){|x| to_fizzbuzz(x)}.first(100)
=> ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", 
"13", "14", "FizzBuzz", "16", "17", "Fizz", "19", "Buzz", "Fizz", "22", "23", "Fizz", 
"Buzz", "26", "Fizz", "28", "29", "FizzBuzz", "31", "32", "Fizz", "34", "Buzz", 
"Fizz", "37", "38", "Fizz", "Buzz", "41", "Fizz", "43", "44", "FizzBuzz", "46", "47", 
"Fizz", "49", "Buzz", "Fizz", "52", "53", "Fizz", "Buzz", "56", "Fizz", "58", "59", 
"FizzBuzz", "61", "62", "Fizz", "64", "Buzz", "Fizz", "67", "68", "Fizz", "Buzz", 
"71", "Fizz", "73", "74", "FizzBuzz", "76", "77", "Fizz", "79", "Buzz", "Fizz", "82", 
"83", "Fizz", "Buzz", "86", "Fizz", "88", "89", "FizzBuzz", "91", "92", "Fizz", "94", 
"Buzz", "Fizz", "97", "98", "Fizz", "Buzz"]

irb> def newton(n)
irb> iterate(n) {|x| (x + n / x) / 2.0}
irb> end
=> :newton
irb> newton(2).first(10)
=> [2, 1.5, 1.4166666666666665, 1.4142156862745097, 1.4142135623746899, 
1.414213562373095, 1.414213562373095, 1.414213562373095, 1.414213562373095, 
1.414213562373095]
irb> newton(3).first(10)
=> [3, 2.0, 1.75, 1.7321428571428572, 1.7320508100147274, 1.7320508075688772, 
1.7320508075688772, 1.7320508075688772, 1.7320508075688772, 1.7320508075688772]
リスト : 素数列 (myprime.rb)

class Myprime
  @@primes = [2, 3, 5]    # 求めた素数を格納

  # 次の素数を求める
  def Myprime.next_prime(n)
    while true
      for p in @@primes
        return n if p * p > n
        break if n % p == 0
      end
      n += 2
    end
  end

  # 素数列の生成
  def Myprime.make
    Enumerator.new(Float::INFINITY) {|y|
      n = 0
      while true
        if n == @@primes.size
          @@primes.push Myprime.next_prime(@@primes[-1] + 2)
        end
        y << @@primes[n]
        n += 1
      end
    }.lazy
  end
end
irb> load "myprime.rb"
=> true
irb> ps = Myprime.make
=> #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator: ... >:each>>
irb> ps.first(25)
=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 
79, 83, 89, 97]
irb> ps.first(100)
=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 
79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 
173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 
269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 
373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 
467, 479, 487, 491, 499, 503, 509, 521, 523, 541]
irb> ps.drop(1000).first(10)
=> [7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017]

●参考 URL


Fiber

irb(main)> co = Fiber.new {
irb(main)> for x in 1 .. 4
irb(main)> Fiber.yield x
irb(main)> end
irb(main)> 5
irb(main)> }
=> #<Fiber:0x834bd24>
irb> co.resume
=> 1
irb> co.resume
=> 2
irb> co.resume
=> 3
irb> co.resume
=> 4
irb> co.resume
=> 5
irb> co.resume
FiberError: dead fiber called

●簡単な例題

リスト : 複数のコルーチン

def print_code(code)
  loop {
    print code
    Fiber.yield true
  }
end

def test_a(n)
  xs = ["h", "e", "y", "!", " "].map {|x| Fiber.new {print_code(x)}}
  n.times {
    xs.each {|co| co.resume}
  }
end
irb> test_a(5)
hey! hey! hey! hey! hey! => 5
irb> test_a(10)
hey! hey! hey! hey! hey! hey! hey! hey! hey! hey! => 10
リスト : 順列の生成

def perm_sub(xs, n)
  if xs.size == n
    Fiber.yield []
  else
    co = Fiber.new { perm_sub(xs, n + 1) }
    while ys = co.resume
      for x in xs
        if not ys.member? x
          Fiber.yield(ys + [x])
        end
      end
    end
  end
end

def permutation(xs)
  Fiber.new { perm_sub(xs, 0) }
end
irb> co = permutation([1,2,3])
=> #<Fiber: ... >
irb> while xs = co.resume
irb> print xs, "\n"
irb> end
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
=> nil
リスト : エラトステネスの篩

# n から始まる整数列
def integers(n)
  Fiber.new {
    loop {
      Fiber.yield n
      n += 1
    }
  }
end

# フィルター
def filter(src)
  Fiber.new {
    while m = src.resume
      Fiber.yield(m) if yield(m)
    end
  }
end

def sieve(x)
  nums = integers(2)
  x.times {
    n = nums.resume
    print n, " "
    nums = filter(nums) {|x| x % n != 0}
  }
end
irb> sieve 25
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 => 25
irb> sieve 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 
109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 
229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 
353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 
479 487 491 499 503 509 521 523 541 => 100

Copyright (C) 2017 Makoto Hiroi
All rights reserved.

[ PrevPage | R u b y | NextPage ]