Home > Net >  In Ruby, is it possible to do arithmetic with symbols?
In Ruby, is it possible to do arithmetic with symbols?

Time:12-11

In Ruby, I'd like to be able to do something like this:

days_of_week = %i(Sunday Monday Tuesday Wednesday Thursday Friday Saturday) 
today = :Sunday
today = today   1
if today > :Saturday
    today = :Sunday
end

This gives me
'undefined method ' ' for :Sunday:Symbol (NoMethodError)

Can I define a method somehow?

I've looked at various stack overflow questions on enums, and didn't see what I'm looking for, but it's a large volume of information to sort through.

CodePudding user response:

This code, as it is, does not work in ruby (as you noticed). Symbol :Sunday does not know that it's placed in an array, so adding a 1 to it does not make any sense.

You can compare symbols like that, but the results will surprise you. :Wednesday is greater than :Thursday, for example.

Why not just operate on indexes in the array. With integer indexes you can increment them and compare with expected results. Could look like this, for example:

today = days_of_week.index(:Friday)
puts "tomorrow is #{days_of_week[today   1]}" # >> tomorrow is Saturday

CodePudding user response:

I think I would create an index with as many entries as necessary to describe what you are trying to do.

Here is a hash of hashes to hold the index and next/prev logical day:

days_of_week = %i(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)

idx=Hash.new {|h, k| h[k] = {} }
days_of_week.each_with_index{ |e,i| 
    idx[e][:idx]=i
    idx[e][:next_day]=
        (i 1)==days_of_week.length ? days_of_week[0] : days_of_week[i 1]
    idx[e][:prev_day]=
        i==0 ? days_of_week[-1] : days_of_week[i-1]     
}

# {:Sunday=>{:idx=>0, :next_day=>:Monday, :prev_day=>:Saturday}, :Monday=>{:idx=>1, :next_day=>:Tuesday, :prev_day=>:Sunday}, :Tuesday=>{:idx=>2, :next_day=>:Wednesday, :prev_day=>:Monday}, :Wednesday=>{:idx=>3, :next_day=>:Thursday, :prev_day=>:Tuesday}, :Thursday=>{:idx=>4, :next_day=>:Friday, :prev_day=>:Wednesday}, :Friday=>{:idx=>5, :next_day=>:Saturday, :prev_day=>:Thursday}, :Saturday=>{:idx=>6, :next_day=>:Sunday, :prev_day=>:Friday}}

Then you can get the next day or previous day:

idx[:Tuesday][:next_day]
# Wednesday
idx[:Saturday][:next_day]
# Wraps around to Sunday

You can create a compare:

def cmp(x,y, idx)
    idx[x][:idx]<=>idx[y][:idx]
    end

So that :Wednesday is properly less than :Thursday

cmp(:Wednesday, :Thursday, idx)
-1

Or sort another array of symbols into the order of the index:

%i(Saturday Sunday Tuesday Thursday Wednesday Friday Monday).
sort_by{ |day| idx[day][:idx] } 
# [:Sunday, :Monday, :Tuesday, :Wednesday, :Thursday, :Friday, :Saturday]

Those types of function can be added to a class to represent the type of symbols you want to deal with.

  • Related