2017-05-08 45 views
0

我想測試一個數範圍爲1內n下降到26,但對於已經重複數字的值(因此11,22):試驗在範圍數目,除了某些值

(n=24).between?(1, 26) # => true, ok 
(n=1).between?(1, 26) # => true, ok 
(n=11).between?(1, 26) # => true (but I want this to return false) 

有沒有更好的方式來實現這一目標不是做:

[*1..10, *12..21, *23..26].include?(n) 

回答

4

有沒有更好的方式來實現這一目標不是做:

[*1..10, *12..21, *23..26].include?(n) 

是的,當然。從較簡單的部分組成複雜的檢查。第一部分檢查的範圍內,重複數字

n.between?(1, 26) && !has_repeated_digits?(n) 

另一個廢品號在哪裏檢查重複的數字可以這樣實現:

def has_repeated_digits?(n) 
    n.to_s.chars.uniq != n.to_s.chars 

    # or, in newer rubies (2.4+) 
    n.digits.uniq != n.digits 
end 

或者,你可以犧牲一些內存,以避免在計算和存儲所有你的「無效」數字在Set或其他東西。您可以根據需要更改此設置,並且不需要觸摸原始狀態。抽象的美。

+0

建議打破支票必將使其更具可讀性,謝謝! – FloatingRock

0

創建一個散列。用數字填充散列以跳過。並檢查所有腦幹鍵:

a = [11, 22] 
h = Hash[a.map {|x| [x, 1]}] 
n=24 

n.between?(1, 26) && !h.key?(n) 
+0

對於這樣的散列,如果你不關心值,只有鍵存在,它在語義上更好使用'Set'。 –

+1

@SergioTulentsev:Plot twist:Ruby的['Set'](http://ruby-doc.org/stdlib-2.4.1/libdoc/set/rdoc/Set.html)只是一個哈希,我們不會關心價值。 :)我確實明白你的觀點。 –

+2

@EricDuminil:是的,我知道。我說「_semantically_ better」:) –

0

短一點:

a=(1..26).to_a - [11,22] 

然後,使用include?方法。

(請注意,它會刪除所有實例)

2

如果範圍是有限的,精確的爲你的情況,你正在做的不錯。一個更好的方法是減法。

([*1..26] - [11, 22]).include?(n=11) 

其他方法肯定會更好,但不會超過您的用例所需的更多計算。

正如評論,陣列建築太昂貴,如果你在你的應用程序中定義的constantsglobal variables一個概念,那麼你可以像下面的初始化過程中定義常量:

ARRAY_RANGE = [*1..26] - [11, 22] 

當你必須檢查,你只需要:

ARRAY_RANGE.include?(n=11) 
+1

數組查找是O(N)。並且構建陣列也不是免費的。但對於這樣的小型數組,這可能並不重要。 –

+0

@SergioTulentsev到底!由於範圍被定義並且很短,因此可以忽略不計。 –

+0

通過使用'Set'而不是數組可以大大提高性能。 O(1)查找FTW :) –

1
24.between?(1, 26) && !(24%100%11).zero? # => true 
1.between?(1, 26) && !(1%100%11).zero? # => true 
11.between?(1, 26) && !(11%100%11).zero? # => false 
22.between?(1, 26) && !(22%100%11).zero? # => false 
+0

另外,在這個例子中,22也不應該通過支票。 –

+0

@SergioTulentsev它沒有。 '22. between?(1,26)&&!(22%100%11).zero? #=>假' – sawa

+0

啊,的確,我愚蠢。 –