2016-10-11 83 views
0

我正在用Ruby解決'100 doors' problem from Rosetta Code。簡單地說,紅寶石100門返回100無

  • 有100門,全封閉,指定1至100
  • 100通行證由,指定1至100
  • 第i傳球,每次第i門「切換」:打開如果它關閉,如果打開時關閉
  • 確定完成100次通過後每個門的狀態。

因此,在第一次通過所有門打開。第二次偶數門關閉。在第三關門i上,其中i%3 == 0已切換,等等。

這是我解決問題的嘗試。

visit_number = 0 
door_array = [] 
door_array = 100.times.map {"closed"} 

until visit_number == 100 do 
    door_array = door_array.map.with_index { |door_status, door_index| 
    if (door_index + 1) % (visit_number + 1) == 0 
     if door_status == "closed" 
     door_status = "open" 
     elsif door_status == "open" 
     door_status = "closed" 
     end 
    end 
    } 
    visit_number += 1 
end 

print door_array 

但它一直打印我100爲零的數組,當我運行它:Look at all this nil !

我在做什麼錯?

+2

作爲一個說明,在處理打開狀態時,通常最好在內部表示爲'true' /'false'。這比同一事物的字符串表示不那麼混亂。當你想要的時候,你可以用正確的標籤來渲染它們。另外,'open =!open'比這個測試字符串的大'if'更容易理解。此外,'Array.new(100,'closed')'在每個插槽中生成一個具有'關閉'的100元素數組。 – tadman

+1

一般提示,請考慮使用'with_index(1)'。 –

+0

在tadman的評論中捎帶,如果我正在接近這個問題,我會創建一個Door類來跟蹤它是否打開或關閉,並有一個'#toggle!'方法來在內部切換狀態。你正在用Ruby寫這篇文章 - 我建議利用該語言的優勢。 – Matt

回答

0

這就是您的if條款返回。只需顯式添加一個返回值。

until visit_number == 100 do 
    door_array = door_array.map.with_index { |door_status, door_index| 
    if (door_index + 1) % (visit_number + 1) == 0 
     if door_status == "closed" 
     door_status = "open" 
     elsif door_status == "open" 
     door_status = "closed" 
     end 
    end 
    door_status 
    } 
    visit_number += 1 
end 

OR:

1.upto(10) {|i| door_array[i*i-1] = 'open'} 
0

的問題是外if塊不明確返回任何東西(因此返回nil隱含的)當條件不符合。

速戰速決:

visit_number = 0 
door_array = [] 
door_array = 100.times.map {"closed"} 

until visit_number == 100 do 
    door_array = door_array.map.with_index { |door_status, door_index| 
    if (door_index + 1) % (visit_number + 1) == 0 
     if door_status == "closed" 
     door_status = "open" 
     elsif door_status == "open" 
     door_status = "closed" 
     end 
    else #<------------- Here 
     door_status #<------------- And here 
    end 
    } 
    visit_number += 1 
end 

print door_array 
0

考慮這兩種方法:

door_array.map { |door| 
    case door 
    when "open" 
    "closed" 
    when "closed" 
    "open" 
    end 
} 

rule = { "open" => "closed", "closed" => "open" } 
door_array.map { |door| rule[door] } 

door_array.map { |door| door == 'open' ? 'closed' : 'open' } 
+0

案例中的'door ='賦值完全沒有意義。那個變量被扔掉了。價值本身就足夠了。 – tadman

+0

@tadman,謝謝你的提示,已刪除。 –

+0

塊內的'door ='賦值完全沒有意義。那個變量被扔掉了。價值本身就足夠了。 –

0

代碼

require 'prime' 

def even_nbr_divisors?(n) 
    return false if n==1 
    arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } } 
    arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even? 
end 

closed, open = (1..100).partition { |n| even_nbr_divisors?(n) } 
closed #=> [ 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 
     # 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 
     # 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 
     # 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 
     # 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 
     # 92, 93, 94, 95, 96, 97, 98, 99], 
open #= [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 

說明

所有的門都關閉開始。考慮第24門。它下面的次經過時被觸發:

pass 1: opened 
pass 2: closed 
pass 3: opened 
pass 4: closed 
pass 6: opened 
pass 8: closed 
pass 12: opened 
pass 24: closed 

注意,門對每個24的除數的切換一次。因此,如果我們有一個方法divisors(n)是返回n的除數的數組,我們能夠確定切換的數量如下:

nbr_toggles = divisors(24).size 
    #=> [1,2,3,4,6,8,12,24].size 
    #=> 8 

由於門被切換爲偶數的時候,我們得出這樣的結論在塵埃落定之後將處於原始狀態(關閉)。同樣,對於n = 9

divisors(9).size 
    #=> [1,3,9].size 
    #=> 3 

因此,我們得出結論:門#9將在年底開放的,因爲3是奇數。

divisors可定義如下。

def divisors(n) 
    arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } } 
    arr.first.product(*arr[1..-1]).map { |a| a.reduce(:*) } 
end 

例如,

divisors 24 
    #=> [1, 3, 2, 6, 4, 12, 8, 24] 
divisors 9 
    #=> [1, 3, 9] 
divisors 1800 
    #=> [1, 5, 25, 3, 15, 75, 9, 45, 225, 2, 10, 50, 6, 30, 150, 18, 90, 450, 
    # 4, 20, 100, 12, 60, 300, 36, 180, 900, 8, 40, 200, 24, 120, 600, 72, 
    # 360, 1800] 

由於我們只當有奇數或偶數除數的關心,我們可以改爲寫

def even_nbr_divisors?(n) 
    return false if n==1 
    arr = Prime.prime_division(n).map { |v,exp| (0..exp).map { |i| v**i } } 
    arr.shift.product(*arr).map { |a| a.reduce(:*) }.size.even? 
end 

n = 24,其操作步驟如下:

n = 24 
a = Prime.prime_division(n) 
    #=> [[2, 3], [3, 1]] 
arr = a.map { |v,exp| (0..exp).map { |i| v**i } } 
    #=> [[1, 2, 4, 8], [1, 3]] 
b = arr.shift 
    #=> [1, 2, 4, 8] 
arr 
    #=> [[1, 3]] 
c = b.product(*arr) 
    #=> [[1, 1], [1, 3], [2, 1], [2, 3], [4, 1], [4, 3], [8, 1], [8, 3]] 
d = c.map { |a| a.reduce(:*) } 
    #=> [1, 3, 2, 6, 4, 12, 8, 24] 
e = d.size 
    #=> 8 
e.even? 
    #=> true 

最後,

(1..100).partition { |n| even_nbr_divisors?(n) } 

返回上面顯示的結果。