2017-10-14 190 views
0

說你有一個列表[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個或更多個元素,那麼如果您不知道最大比較次數,那麼如何編寫一個循環或者實現了這個循環?

回答

2

我們在紅寶石一個有用的方法來做到這一點,那就是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

+1

您可以在'Array#combination'之後移除'Enumerator#to_a'。我不能刪除它,因爲它少於6個字符。 –

0

這個問題還不清楚。首先,標題含糊不清,詢問如何實施一個未明確問題的特定方法。你一開始就需要的是一個關於這個問題的聲明。

我會猜一猜這個陳述可能是什麼,然後提出一個解決方案。

鑑於

  • 陣列arr;
  • 一個正整數n,1 <= n <= arr.size;和具有
  • 的方法mn論據是arr返回truefalse不同元件,以返回truearr原因mn元件

什麼組合?

我們可以使用以下方法結合方法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(這使得它在紅寶石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 

通過將散列的默認值設置爲零,如果它沒有密鑰kVOWEL_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

0

我覺得每個人都在使這個複雜得多,它是。你肯定指出了正確的方向(Array#combination,Array#repeated_combination,Array#permutation,Array#repeated_permutation)。爲了完成你正在做確切的事情,你可以簡單地做:

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

檢查上面的鏈接,看看它們之間的區別。

如果你想創建一個輔助方法,你可以,但在我看來這不是真的需要在這種情況下。將2替換爲您正在查找的號碼,然後獲得答案。