Подтвердить что ты не робот

Создать буквы для представления числа с использованием рубина?

Я хотел бы сгенерировать последовательность букв, то есть "A", "DE" "GJE" и т.д., которые соответствуют числу. Первые 26 довольно легко, поэтому 3 возвращает "C", 26 возвращает "Z", а 27 вернет "AA", 28 "AB" и так далее.

То, что я не могу понять, - это как сделать это, чтобы он обрабатывал любое число, пройденное. Так что, если я перейду в 4123, я должен вернуть некоторую комбинацию из 3 букв, поскольку (26 * 26 * 26) позволяет для до +17 000 комбинаций.

Любые предложения?

4b9b3361

Ответ 1

class Numeric
  Alph = ("a".."z").to_a
  def alph
    s, q = "", self
    (q, r = (q - 1).divmod(26)); s.prepend(Alph[r]) until q.zero?
    s
  end
end

3.alph
# => "c"
26.alph
# => "z"
27.alph
# => "aa"
4123.alph
# => "fbo"

Ответ 2

Подстройка оригинального ответа @sawa для Ruby 2.0, так как я не мог заставить его работать как есть:

class Numeric
  Alpha26 = ("a".."z").to_a
  def to_s26
    return "" if self < 1
    s, q = "", self
    loop do
      q, r = (q - 1).divmod(26)
      s.prepend(Alpha26[r]) 
      break if q.zero?
    end
    s
  end
end

и здесь происходит обратное преобразование строки в целое число:

class String
  Alpha26 = ("a".."z").to_a

  def to_i26
    result = 0
    downcased = downcase
    (1..length).each do |i|
      char = downcased[-i]
      result += 26**(i-1) * (Alpha26.index(char) + 1)
    end
    result
  end

end

Использование:

1234567890.to_s26 
# => "cywoqvj"

"cywoqvj".to_i26  
# => 1234567890

1234567890.to_s26.to_i26
# => 1234567890

"".to_i26
# => 0

0.to_s26
# => ""

Ответ 3

Строки имеют метод succ, поэтому они могут использоваться в диапазоне. Преемником "Z" является "AA", поэтому это работает:

h = {}
('A'..'ZZZ').each_with_index{|w, i| h[i+1] = w } 
p h[27] #=> "AA"

Ответ 4

Мне понравился этот ответ: fooobar.com/questions/376364/...

number.to_s(26).tr("0123456789abcdefghijklmnopq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

Ответ 5

Используя метод базовой конверсии, нашла здесь. Я также изменил его на отсутствие "0", которое у нас есть в этой системе нумерации. Были рассмотрены случаи окончания.

def baseAZ(num)
  # temp variable for converting base
  temp = num

  # the base 26 (az) number
  az = ''

  while temp > 0

    # get the remainder and convert to a letter
    num26 = temp % 26
    temp /= 26

    # offset for lack of "0"
    temp -= 1 if num26 == 0

    az = (num26).to_s(26).tr('0-9a-p', 'ZA-Y') + az
  end

  return az
end

irb I/O:

>> baseAZ(1)
=> "A"
>> baseAZ(26^2 + 1)
=> "Y"
>> baseAZ(26*26 + 1)
=> "ZA"
>> baseAZ(26*26*26 + 1)
=> "YZA"
>> baseAZ(26*26*26 + 26*26 + 1)
=> "ZZA"

Ответ 6

def letter_sequence(n)
    n.to_s(26).each_char.map {|i| ('A'..'Z').to_a[i.to_i(26)]}.join
end

Ответ 7

Основываясь на ответе на пишу, мне нужен метод, который работал независимо, хотя и рекурсивно, для достижения желаемого результата:

def num_to_col(num)
  raise("invalid value #{num} for num") unless num > 0
  result, remainder = num.divmod(26)
  if remainder == 0
    result -= 1
    remainder = 26
  end
  final_letter = ('a'..'z').to_a[remainder-1]
  result > 0 ? previous_letters = num_to_col(result) : previous_letters = ''
  "#{previous_letters}#{final_letter}".upcase
end

Ответ 8

Вот краткое рекурсивное решение на основе производительности

class Numeric
  # 'z' is placed in the begining of the array because 26 % 26 is 0 not 26
  Alph = ['z'] + ("a".."y").to_a

  def to_alph

    # if self is 0 or negative return a blank string.
    # this is also used to end the recursive chain of to_alph calls
    # so don't replace this with raising an error or returning anything else

    return '' if self < 1

    # (otherwise) return two concatenated strings:
    # the right side is the letter for self modules 26
    # the left side is comprised of:
    #  1. minus one, because this is not a zero-based numbering system.
    #     therefore, round numbers (26, 52...) should return one digit 'z'
    #     instead of two digits 'aa' or 'ba'.
    #  2. divide by 26 and call to_alph on that.
    #     this repeats recursively for every digit of the final string,
    #     plus once more that will return '' to end the recursion chain.

    return ((self - 1) / 26).to_alph + Alph[self % 26]
  end
end