Note: three solutions are shown; find cleavage.
Describe a real number, then (1..INFINITE).select{|n| valid(n)}.take(1) (1..INFINITE).select{|n| valid(n)}.take(1)
So what really is? Well, allow yourself to take advantage here:
class Fixnum def to_a to_s.split('').collect{|d| d.to_i} end end 123.to_a == [1,2,3]
So now: Each digit can be a digit already present or zero, or a digit larger than the previous value, and the first digit is always valid.
PS - I use i not i-1 because the loop index is less than set 's, since I disabled the first element.
def valid num #Ignore zeros: set = num.to_a.select{|d| d != 0 } #First digit is always valid: set[1..-1].each_with_index{ |d, i| if d > set[i] # puts "Increasing digit" elsif set[0..i].include? d # puts "Repeat digit" else # puts "Digit does not pass" return false end } return true end
So, cheers for the lazy:
(1..Float::INFINITY).lazy.select{|n| valid n}.take(100).force
Now that we have this, make it concise:
def valid2 num set = num.to_a.select{|d| d != 0 } set[1..-1].each_with_index{ |d, i| return false unless (d > set[i]) || (set[0..(i)].include? d) } return true end
check:
(1..Float::INFINITY).lazy.select{|n| valid n}.take(100).force - (1..Float::INFINITY).lazy.select{|n| valid2 n}.take(100).force
all together now:
def valid num set = num.to_s.split('').collect{|d| d.to_i}.select{|d| d != 0 } set[1..-1].each_with_index{ |d, i| return false unless (d > set[i]) || (set[0..(i)].include? d) } return true end
Edit: If you want a specific subset of the set, just change the range. Your original will look like this:
(500..1000).select{|n| valid n}
Edit2: To create a range for a given number of digits n :
((Array.new(n-1, 0).unshift(1).join('').to_i)..(Array.new(n, 0).unshift(1).join('').to_i))
Edit3: An interesting alternative method is to delete digits recursively when they become valid.
def _rvalid set return true if set.size < 2 return false if set[1] < set[0] return _rvalid set.select{|d| d != set[0]} end def rvalid num return _rvalid num.to_s.split('').collect{|d| d.to_i}.select{|d| d != 0 } end (1..Float::INFINITY).lazy.select{|n| rvalid n}.take(100).force
Edit 4: Positive Generation Method
def _rgen set, target return set if set.size == target ((set.max..9).to_a + set.uniq).collect{ |d| _rgen((set + [d]), target) } end def rgen target sets = (0..9).collect{|d| _rgen [d], target }