Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails loop through 'A..Z' and beyond?

I need to generate a unique name based on a start_date of a model. I have the following code that's working. However, as you can see, it only supports up to letter Z. Is there a way that I can make it work for beyond Z, like this sequence? A,B,C,...X,Y,Z,AA,AB,AC,AD,AE...AZ,BA,BB,BC...

  def generate_name
    ("A".."Z").each do |letter|
      random_token = start_date.strftime("%m%d%y") + letter
      break random_token unless Tour.where(name: random_token).exists?
    end
  end
like image 887
netwire Avatar asked Oct 17 '25 02:10

netwire


2 Answers

def letters
  ('a'..'z').each { |i| yield i }
  letters do |i|
    ('a'..'z').each { |j| yield i+j }
  end
end

def generate_name
  letters do |letter|
    random_token = start_date.strftime("%m%d%y") + letter
    break random_token unless Tour.where(name: random_token).exists?
  end
end
like image 193
Sam Ruby Avatar answered Oct 18 '25 21:10

Sam Ruby


Sam's answer looks like exactly what you requested but here's another possibly useful way to look at your problem:

Think of your string as a number in base 26, where the digits are represented by 'a'..'z'. The only difference between doing it this way and the way you requested is that the first two-digit number (err, two-letter string) will be ba rather than aa (assuming that you started counting with a = 0, b = 1, etc.) and you won't generate any strings starting with a (other than the first one) for the same reason you don't write whole numbers starting with 0 (other than the first one).

If it's useful for you to calculate very quickly that the name dw was the 100th one you generated, then this approach has merit. It's also a good way to work the word hexavigesimal into conversations or at least into documentation.

like image 44
Mark Westling Avatar answered Oct 18 '25 19:10

Mark Westling



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!