如何使用不确定的嵌套循环创建循环?

时间:2017-10-14 01:52:43

标签: ruby loops

说你有一个清单[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个或更多个元素,那么如果你不知道最大比较数,那么如何编写循环或实现此目的的东西呢?

3 个答案:

答案 0 :(得分:2)

我们在ruby中有一个有用的方法来做到这一点,那就是Array#combination

def find_odd_sums(list, num_per_group)
  list.combination(num_per_group).to_a.map(&:sum).select(&:odd?)
end

如果您愿意,可以重新实施combinationAlgorithm to return all combinations of k elements from n

提供了此功能的许多版本

答案 1 :(得分:0)

这个问题不明确。首先,标题是模糊的,询问如何实现对未说明问题的特定方法。在一开始,你需要的是用问题的语言表达的声明。

我将猜测该陈述可能是什么,然后提出解决方案。

鉴于

  • 数组arr;
  • 正整数n1 <= n <= arr.size;和
  • 方法mn个参数是arr的不同元素,返回truefalse

n arr元素的哪些组合导致m返回true

我们可以使用以下方法结合方法m的定义。

def combos(arr, n, m)
  arr.combination(n).select { |x| public_send(m, *x) }
end

当然,关键是方法Array#combination。另请参阅方法Enumerable#selectObject#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的文档(这是在Ruby v2.4中首次亮相。

这是第二个例子:给定一个字母数组,五个字母的组合有两个元音?

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

通过将哈希的默认值设置为零,如果VOWEL_COUNTER[k]没有键k,则{0}将返回零。例如,

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_inil转换为零。

另请参阅#select,#public_send

方法的文档

答案 2 :(得分:0)

我觉得每个人都比这更复杂。你确定指向了正确的方向(Array#combinationArray#repeated_combinationArray#permutationArray#repeated_permutation)。要完成你正在做的事情,你可以简单地做:

list.repeated_combination(2) { |c| puts c.sum if c.sum.odd? }

检查上面的链接,看看它们之间的区别。

如果你想创建一个帮助方法,但在我看来,在这种情况下并不是真的需要它。将2替换为您要查找的号码,您就得到了答案。