红宝石多个代码块如何连接/链接时



这是Ruby中的一个函数,可以找到数组中的2个唯一数字加起来:

def sum_eq_n? (arr, n)
    return true if arr.empty? && n == 0
    p "first part array:" + String(arr.product(arr).reject { |a,b| a == b })
    puts "n"
    p "first part bool:" + String(arr.product(arr).reject { |a,b| a == b }.any?)
    puts "n"
    p "second part:" + String(arr.product(arr).reject { |a,b| a + b == n } )
    puts "n"
    result = arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }
    return result
end
#define inputs
l1 = [1, 2, 3, 4, 5, 5]
n = 10
#run function
print "Result is: " + String(sum_eq_n?(l1, n))

我很困惑计算如何产生结果。如您所见,我已经将功能分为几个部分,以可视化。我已经研究并了解.reject.any?方法。

但是,我仍然对它在1衬里中的合适方式感到困惑。如何组合评估两个块?之后,我只找到了带有1个代码块的.reject的示例。.reject是否应用于两者?我还认为可能有一个隐式和在两个代码块之间,但是我试图添加一个第三个虚拟块,并且失败了,所以在这一点上,我根本不确定它是如何工作的。

您可以通过这些等效替代来解释表达式:

# orig
arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }
# same as
pairs = arr.product(arr)
pairs.reject { |a,b| a == b }.any? { |a,b| a + b == n }
# same as
pairs = arr.product(arr)
different_pairs = pairs.reject { |a,b| a == b }
different_pairs.any? { |a,b| a + b == n }

每个块是相应方法的一个参数 - 一个用于reject,一个用于any?。它们按顺序进行评估,并且不是组合。构成表达式的零件可以包裹在括号中以显示以下内容:

((arr.product(arr)).reject { |a,b| a == b }).any? { |a,b| a + b == n }
# broken up lines:
(
  (
    arr.product(arr)          # pairs
  ).reject { |a,b| a == b }   # different_pairs
).any? { |a,b| a + b == n }

Ruby中的块是方法参数

Ruby中的

块是一流的语法结构,用于将封闭作为参数传递给方法。如果您比功能性的概念更熟悉面向对象的概念,那么这里是对象(一种(封闭的示例:

class MultiplyPairStrategy
  def perform(a, b)
    a * b
  end
end
def convert_using_strategy(pairs, strategy)
  new_array = []
  for pair in pairs do
    new_array << strategy.perform(*pair)
  end
  new_array
end
pairs = [
  [2, 3],
  [5, 4],
]
multiply_pair = MultiplyPairStrategy.new
convert_using_strategy(pairs, multiply_pair) # => [6, 20]

与:

相同
multiply_pair = Proc.new { |a, b| a * b }
pairs.map(&multiply_pair)

与最惯用的人相同:

pairs.map { |a, b| a * b }

第二种方法返回并使用了第一个方法的返回结果。

这个:

result = arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }

功能等效于:

results = arr.product(arr).reject { |a,b| a == b} # matrix of array pairs with identical values rejected
result = results.any? { |a,b| a + b == n }  #true/false

最好在pry(注释我的(

中观察到这一点。
[1] pry(main)> arr = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
[2] pry(main)> n = 10
=> 10
[3] pry(main)> result_reject = arr.product(arr).reject { |a,b| a == b } # all combinations of array elements, with identical ones removed
=> [[1, 2],
 [1, 3],
 [1, 4],
 [1, 5],
 [1, 5],
 [2, 1],
 [2, 3],
 [2, 4],
 [2, 5],
 [2, 5],
 [3, 1],
 [3, 2],
 [3, 4],
 [3, 5],
 [3, 5],
 [4, 1],
 [4, 2],
 [4, 3],
 [4, 5],
 [4, 5],
 [5, 1],
 [5, 2],
 [5, 3],
 [5, 4],
 [5, 1],
 [5, 2],
 [5, 3],
 [5, 4]]
[4] pry(main)> result_reject.any? { |a,b| a + b == n } # do any of the pairs of elements add together to equal ` n` ?
=> false
[5] pry(main)> arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }  # the one liner
=> false

每个操作"链"进入下一个,可视化看起来像:

arr.product(arr).reject { |a,b| a == b }.any? { |a,b| a + b == n }
|--|------A----->-----------B----------->-------------C----------|

当A部分(调用.product(arr)(评估对象。该对象具有随后调用的reject方法,并且该对象具有依次调用的any?方法。这是a.b.c.d的精美版本,其中一个调用用于生成后续调用的对象。

从此不明显的是,product返回枚举器,这是一个可以用于获取结果的对象,但不是实际结果。这更像是返回结果的意图,以及以多种方式获取它们的能力。这些可以链式链接以获取所需的最终产品。

作为注意,此代码可以简化为:

arr.repeated_permutation(2).map(&:sum).include?(n)

repeated_permutation方法为您提供了所有2位数字组合,而无需重复数字。通过更改该参数,可以轻松地将其扩展到 n 数字。include?是否存在目标。

如果您正在使用大型阵列,则可能需要稍微优化:

arr.repeated_permutation(2).lazy.map(&:sum).include?(n)

在第一次比赛中将停止的地方并避免进一步的总和。lazy调用的效果是传播单个值直到链的末端,而不是链的每个阶段,然后再转发到下一个。

lazy的想法是关于枚举的有趣的事情之一。您可以控制值如何流过这些链。

最新更新