序列发生器,kata,ruby

时间:2016-03-10 07:07:44

标签: ruby-on-rails ruby algorithm enumerator

我正在通过Ruby做这个'序列生成器'Kata,不知何故我不知道如何实现这一点。但我试过了。请给我一些额外的帮助。谢谢!

  

编写生成器sequence_gen(JavaScript中的sequenceGen),给定序列的第一项将生成(可能)无限量的术语,其中每个后续术语是先前x术语的总和,其中x是数量初始参数(此类序列的例子是Fibonacci,Tribonacci和Lucas数字序列)。

示例:

fib = sequence_gen(0, 1) # returns an Enumerator
fib.next = 0 # first term (provided)
fib.next = 1 # second term (provided)
fib.next = 1 # third term (sum of first and second terms)
fib.next = 2 # fourth term (sum of second and third terms)
fib.next = 3 # fifth term (sum of third and fourth terms)
fib.next = 5 # sixth term (sum of fourth and fifth terms)
fib.next = 8 # seventh term (sum of fifth and sixth terms)


trib = sequence_gen(0,1,1) # returns an Enumerator
trib.next = 0 # first term (provided)
trib.next = 1 # second term (provided)
trib.next = 1 # third term (provided)
trib.next = 2 # fourth term (sum of first, second and third terms)
trib.next = 4 # fifth term (sum of second, third and fourth terms)
trib.next = 7 # sixth term (sum of third, fourth and fifth terms)

lucas = sequence_gen(2,1) # returns an Enumerator
lucas.take(10) = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]

我的解决方案:

def sequence_gen(e, vs)
  while true
    begin
      vs = e.next_values
      return $!.result
    end
    y = yield(*vs)
    e.feed y
  end
end

最佳,

1 个答案:

答案 0 :(得分:2)

守则

您可以在枚举器中使用无限循环,如下所示:

def sequence_gen(*args)
  Enumerator.new do |y|
    args.each { |e| y << e }
    loop do    
      y << sum = args.inject(:+)
      args = args.drop(1).push(sum) 
    end    
  end
end

<强>解释

现在假设您已了解调查员的工作方式。我们假设我们正在使用sequence_gen(0,1) args = [0,1]的例子。考虑这一行:

args.each { |e| y << e }

序列的前几个术语将是传递给sequence_gen(0,1)的参数,即01。这意味着我们首先需要按顺序产生参数0和1。这就是上面代码的作用。

无限循环

loop do    
  y << sum = args.inject(:+)
  args = args.push(sum).drop(1) 
end

此循环的目的是生成序列的其余部分。序列中的下一个数字是前两个参数的 sum ,即01,它们存储在数组args = [0,1]中。我们可以使用inject(:+)来轻松完成此操作。这使sum = 1使用<<通过y获得了1。这也意味着我们序列中的下一个数字也是args = [0,1]

目前0,1,1,我们的序列为1,1。为了获得序列中的下一个数字,我们需要对当前序列中的最后两个数字求和,即args。我们通过转换push(sum)来表示序列的最后两个数字。我们使用args = [0,1,1]提供args = [0,1,1]。然后从arg = [1,1] sum = 2中删除第一个元素。然后我们将这个新数组求和3, 5, 8,这是我们序列中的下一个数字。创建这个新数组是由我们的循环的最后一行完成的。使用第一行完成求和。由于我们处于循环中,因此重复这些步骤,直到产生next等。

take()next做了什么?

在枚举器中定义无限循环时,您可以根据需要控制输出流。

y获取下一个产生的值next。在我们的示例中,根据枚举器中代码的顺序,调用0一次指示y产生next。再次呼叫1会产生take(4)。这是使用代码的第一部分(循环之前)完成的。然后循环保持并产生其余的值,理论上你可以永远这样做(因为你有一个无限循环)。

next取得前4个元素。它类似于按顺序调用take(n)四次,除了将生成的值保存到数组中。同样,因为我们有一个无限循环,理论上我们可以调用n来获得我们想要的大puts 'The first seven terms of fib = sequence_gen(0, 1) are:' fib = sequence_gen(0, 1) # returns an Enumerator p fib.next #=> 0 # first term (provided) p fib.next #=> 1 # second term (provided) p fib.next #=> 1 # third term (sum of first and second terms) p fib.next #=> 2 # fourth term (sum of second and third terms) p fib.next #=> 3 # fifth term (sum of third and fourth terms) p fib.next #=> 5 # sixth term (sum of fourth and fifth terms) p fib.next #=> 8 # seventh term (sum of fifth and sixth terms) puts puts 'The first six terms of trib = sequence_gen(0,1,1) are:' trib = sequence_gen(0,1,1) # returns an Enumerator p trib.next #=> 0 # first term (provided) p trib.next #=> 1 # second term (provided) p trib.next #=> 1 # third term (provided) p trib.next #=> 2 # fourth term (sum of first, second and third terms) p trib.next #=> 4 # fifth term (sum of second, third and fourth terms) p trib.next #=> 7 # sixth term (sum of third, fourth and fifth terms) puts puts 'The first ten terms of lucas = sequence_gen(2,1) are:' lucas = sequence_gen(2,1) # returns an Enumerator p lucas.take(10) #=> [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]

运行代码

然后使用 Enumerator 方法运行上述代码:

The first seven terms of fib = sequence_gen(0, 1) are:
0
1
1
2
3
5
8

The first six terms of trib = sequence_gen(0,1,1) are:
0
1
1
2
4
7

The first ten terms of lucas = sequence_gen(2,1) are:
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]

输出:

$('selector1')
相关问题