Как я могу найти первую повторяющуюся букву строки в Ruby?

У меня есть строка "teststring". Я хочу найти первый повторяющийся символ в Ruby.

У меня есть этот код Python:

def first_non_repeat_character(teststring)
    unique=[]
    repeated=[]
    for character in teststring:
        if character in unique:
            unique.remove(character)
            repeated.append(character)
        else:
            if not character in repeated:
                unique.append(character)
    if len(unique):
        return unique[0]
    else: 
        return false

Ответ 1

Вы можете написать:

str = 'teststring'

arr = str.chars
(arr - (arr.difference(arr.uniq))).first
  #= "e"

где Array#difference определяется в моем ответе здесь.

Array#difference похож на Array#-. Разница проиллюстрирована в следующем примере:

a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]

a     -      b #=> [1]
a.difference b #=> [1, 3, 2, 2]

arr.difference(arr.uniq) поэтому возвращает массив всех элементов e of arr, для которых arr.count(e) > 1.

arr.difference(arr.uniq) возвращает повторяющиеся символы, поэтому

arr - arr.difference(arr.uniq)

возвращает повторяющиеся символы, упорядоченные по порядку в arr.

Ответ 2

def first_non_repeat_character(string)
  string.chars.find { |character| string.count(character) == 1 }
end

first_non_repeat_character('teststring') # => "e"

Ответ 3

Это должно сделать трюк:

def first_non_repeat_character(teststring)
  group = teststring.chars.group_by {|i| i}.find {|letter, group| group.one? }
  group && group.first
end

Так как ruby ​​2.2.1 вы можете использовать group_by(&:itself)

Ответ 4

С кивком к @BroiSatse для основной идеи я предлагаю следующую вариацию в его ответе на цепочку в irb или pry console, если у вас есть Ruby 2.2+ с новым Object # сам:

'teststring'.chars.group_by(&:itself).values.select { |v| v.one? }.flatten.first
#=> "e"

Хорошая вещь об этом подходе (в отличие от определения метода) заключается в том, что легко отменить цепочку методов для отладки. Если вы не получите ответ, который вы ожидаете, просто продолжайте удалять хвост цепи методов, пока не найдете проблему.

Ответ 5

Другой:

'teststring'.each_char.with_object(Hash.new(0)) { |c, h| h[c] += 1 }.key(1)
#=> "e"

Шаг за шагом:

each_char обходит каждого символа:

'teststring'.each_char.to_a
#=> ["t", "e", "s", "t", "s", "t", "r", "i", "n", "g"]

with_object передает a Hash со значением по умолчанию 0 в блок для подсчета каждого символа (возврат хэш):

'teststring'.each_char.with_object(Hash.new(0)) { |c, h| h[c] += 1 }
#=> {"t"=>3, "e"=>1, "s"=>2, "r"=>1, "i"=>1, "n"=>1, "g"=>1}

key возвращает ключ (т.е. символ) для данного значения (т.е. с числом 1)

'teststring'.each_char.with_object(Hash.new(0)) { |c, h| h[c] += 1 }.key(1)
#=> "e"

Возможная оговорка: хотя реализация возвращает первый ключ для данного значения, в документации говорится:

Возвращает ключ вхождения данного значения.

Ответ 6

Вот пример, который учитывает прописные буквы. Например, если вы перейдете в

"sTresst" => "r"

def  first_non_repeating_letter(s) 
  s.each_char do |char|
    return char if s.downcase.count(char.downcase) < 2
  end
  ""
end