如何创建一个无限循环的循环?
说你有一个列表[1,2,3 ...... N] 如果你需要比较两个元素,因此你会写类似如何创建一个无限循环的循环?
list = (0..9999).to_a
idx = 0
while idx < list.length
idx2 = idx
while idx2 < list.length
puts list[idx] + list[idx2] if (list[idx] + list[idx2]).odd?
idx2 += 1
end
idx += 1
end
但是,如果比较的数字是什么不是不断增加? 这段代码通过在一个循环内部对另一个循环进行硬编码,但是如果您需要比较4个或更多个元素,那么如果您不知道最大比较次数,那么如何编写一个循环或者实现了这个循环?
我们在红宝石一个有用的方法来做到这一点,那就是Array#combination:
def find_odd_sums(list, num_per_group)
list.combination(num_per_group).to_a.map(&:sum).select(&:odd?)
end
您可以重新实现combination
,如果你选择。有这个功能有很多版本可用Algorithm to return all combinations of k elements from n
这个问题还不清楚。首先,标题含糊不清,询问如何实施一个未明确问题的特定方法。你一开始就需要的是一个关于这个问题的声明。
我会猜一猜这个陈述可能是什么,然后提出一个解决方案。
鉴于
- 阵列
arr
; - 一个正整数
n
,1 <= n <= arr.size
;和具有 - 的方法
m
n
论据是arr
返回true
或false
不同元件,以返回true
的arr
原因m
n
元件
什么组合?
我们可以使用以下方法结合方法m
的定义。
def combos(arr, n, m)
arr.combination(n).select { |x| public_send(m, *x) }
end
关键当然是方法Array#combination。另请参阅方法Enumerable#select和Object#public_send的文档。
下面是它在问题中给出的例子中的用法。
def m(*x)
x.sum.odd?
end
arr = [1,2,3,4,5,6]
combos(arr, 2, :m)
#=> [[1, 2], [1, 4], [1, 6], [2, 3], [2, 5], [3, 4], [3, 6], [4, 5], [5, 6]]
combos(arr, 3, :m)
#=> [[1, 2, 4], [1, 2, 6], [1, 3, 5], [1, 4, 6], [2, 3, 4], [2, 3, 6],
# [2, 4, 5], [2, 5, 6], [3, 4, 6], [4, 5, 6]]
combos(arr, 4, :m)
#=> [[1, 2, 3, 5], [1, 2, 4, 6], [1, 3, 4, 5], [1, 3, 5, 6], [2, 3, 4, 6], [2, 4, 5, 6]]
参见Array#sum(这使得它在红宝石V2.4登场DOC
这里的一个第二个例子:给定的字母阵列,其中的五个字母的组合有两个元音
?VOWEL_COUNTER = %w| a e i o u |.product([1]).to_h.tap { |h| h.default=0 }
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
VOWEL_COUNTER['a']
#=> 1
通过将散列的默认值设置为零,如果它没有密钥k
,VOWEL_COUNTER[k]
将返回零。例如,
VOWEL_COUNTER['r']
#=> 0
def m(*x)
x.sum { |c| VOWEL_COUNTER[c] } == 2
end
arr = %w| a r t u e v s |
combos(arr, 5, :m)
#=> [["a", "r", "t", "u", "v"], ["a", "r", "t", "u", "s"],
# ["a", "r", "t", "e", "v"], ["a", "r", "t", "e", "s"],
# ["a", "r", "u", "v", "s"], ["a", "r", "e", "v", "s"],
# ["a", "t", "u", "v", "s"], ["a", "t", "e", "v", "s"],
# ["r", "t", "u", "e", "v"], ["r", "t", "u", "e", "s"],
# ["r", "u", "e", "v", "s"], ["t", "u", "e", "v", "s"]]
请注意,VOWEL_COUNTER
构造如下。
a = %w| a e i o u |
#=> ["a", "e", "i", "o", "u"]
b = a.product([1])
#=> [["a", 1], ["e", 1], ["i", 1], ["o", 1], ["u", 1]]
c = b.to_h
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
有了这个哈希,
c['r']
#=> nil
,所以我们需要将默认值设为零。
VOWEL_COUNTER = c.tap { |h| h.default=0 }
#=> {"a"=>1, "e"=>1, "i"=>1, "o"=>1, "u"=>1}
c['r']
#=> 0
或者,我们可以省略最后一步(散列的默认设置为零),并书面
x.sum { |c| VOWEL_COUNTER[c].to_i } == 2
因为NilClass#to_i转换nil
为零。
也请参阅该文档的方法#选择,#public_send
我觉得每个人都在使这个复杂得多,它是。你肯定指出了正确的方向(Array#combination
,Array#repeated_combination
,Array#permutation
,Array#repeated_permutation
)。为了完成你正在做确切的事情,你可以简单地做:
list.repeated_combination(2) { |c| puts c.sum if c.sum.odd? }
检查上面的链接,看看它们之间的区别。
如果你想创建一个辅助方法,你可以,但在我看来这不是真的需要在这种情况下。将2
替换为您正在查找的号码,然后获得答案。
您可以在'Array#combination'之后移除'Enumerator#to_a'。我不能删除它,因为它少于6个字符。 –