这是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
的想法是关于枚举的有趣的事情之一。您可以控制值如何流过这些链。