Функция, которая возвращает количество букв, повторяющихся в строке

Попытка создать функцию, которая подсчитывает количество букв, которые появляются более одного раза в любом месте строки (не обязательно вместе, а не количество повторений). Это то, что у меня есть:

def num_repeats(string)

    repeat = []

    i1 = 0
    i2 = 1
    while i1 < string.length 
        while  i2 < string.length
            if (string[i1] == string[i2]) && (!repeat.include? string[i1]) 
                repeat << string[i1]
            end
            i2 +=1
        end 
        i1+=1
    end

    return repeat.length
end

puts(num_repeats('sldhelanlaskjkajksda'))

По какой-то причине он только толкает первую букву строки, если эта первая буква была использована в остальной части строки, но после этого кажется, что метод останавливается, перейдя через остальную строку.

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

Ответ 1

Вот православный способ сделать это:

'sldhelanlaskjkajksda'.each_char.group_by(&:itself).count{|_, v| v.length > 1}
# => 6


Причина, по которой ваш код не работает, заключается в том, что (i) после того, как цикл i2 завершается, вы увеличиваете i1 и пытаетесь выполнить следующий цикл i2 в следующей итерации i1 , но поскольку i2 hasn ' t был затронут после того, как не удалось удовлетворить условию цикла, он не будет удовлетворять условию снова, и цикл i2 никогда не будет работать снова, и (ii) вы инициализируете i2 константу.

Чтобы исправить это, инициализируйте i2 внутри цикла i1 в начале и инициализируйте его до i2 = i1 + 1, а не 1.

Ответ 2

Другой способ:

s = 'sldhelanlaskjkajksda'

a = s.chars
  #=> ["s", "l", "d", "h", "e", "l", "a", "n", "l", "a",
  #    "s", "k", "j", "k", "a", "j", "k", "s", "d", "a"] 
a.difference(a.uniq).uniq.size
  #=> 6

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

Имеем:

b = a.uniq
  #=> ["s", "l", "d", "h", "e", "a", "n", "k", "j"] 
c = a.difference(b)
  #=> ["l", "l", "a", "s", "k", "a", "j", "k", "s", "d", "a"] 
d = c.uniq
  #=> ["l", "a", "s", "k", "j", "d"] 
d.size
  #=> 6 

Ответ 3

Ни один из этих ответов не считает, что ОП попросил повторить буквы

Но это делает:

'sldhe-lanlas-kjkajksda'.scan(/([a-z])(?=.*\1)/i).uniq.size
#=> 6

Ответ 4

Это решение для вашей проблемы

    def num_repeats(string)
        repeat = []
        i1 = 0
        i2 = 1

        while i1 < string.length
            while  i2 < string.length
                if (string[i1] == string[i2]) && !(repeat.include? string[i1]) 
                    repeat << string[i1]
                end
               i2 +=1
            end 
            i1+=1
            i2 = i1 + 1
        end
        return repeat.length
    end 
    puts(num_repeats('sldhelanlaskjkajksda'))

Ответ 5

Вот немного проще (надеюсь) и немного Ruby-ish, решение:

def num_repeats(string)

    # chars in string
    chars = string.split('')

    # initialize map - for each char, count is initialized to 0
    hash = chars.uniq.inject({}) { |h, c| h[c] = 0; h}

    # for each char in string, lets count its occurrences
    chars.each do |c| 
        hash[c] += 1
    end

    # now lets pick those entries from the map where the count is > 1
    hash_with_repeated_chars = hash.select {|k, v| v > 1 }

    # now lets pick the chars that are repeated by picking keys of hash
    repeated_chars = hash_with_repeated_chars.select { |k, v| k}

    # return the count of repeated chars
    return repeated_chars.count
end

p num_repeats('abc')    # Prints 0
p num_repeats('abbc')   # Prints 1
p num_repeats('abbcc')  # Prints 2
p num_repeats('aabbcc') # Prints 3

У меня также есть версия Ruby, которая отличается от всех других ответов (и, следовательно, бит неэффективен из-за множества итераций, которые он делает внутри)

s = 'sldhelanlaskjkajksda'
p s.chars.combination(2).to_a.uniq.map(&:sort).map(&:uniq).select{|a| a.size.eql?(1)}.count