2014-09-19 9 views
22

Próbuję zliczyć, ile razy łańcuch pojawia się w innym ciągu.Ruby: Jak zliczyć, ile razy łańcuch pojawia się w innym ciągu?

Wiem, że można policzyć ile razy litera pojawi się w ciąg znaków:

string = "aabbccddbb" 
string.count('a') 
=> 2 

Ale jeśli szukać sposobu wyświetlania wielokrotnie „AA” w tym ciągu, ja też dostać dwa.

string.count('aa') 
=> 2 

Nie rozumiem tego. Wstawiam tę wartość w cudzysłów, więc szukam liczby razy, kiedy pojawia się dokładny ciąg znaków, a nie tylko litery.

+2

Proszę wyjaśnić (z edycją): czy 'aa'' pojawia się raz lub dwa razy w ciągu znaków' aaa''. –

+0

Prawdopodobnie powinno to być dwa razy więcej.Pozycje 0 i 1 && Pozycje 1 i 2 – Johnson

+0

Z pewnością jesteś świetnym plakatem. Nagrodziłem cię Cary Swoveland. – Johnson

Odpowiedz

26

Oto kilka sposobów, aby policzyć liczbę razy dany podciąg pojawia się ciąg znaków (pierwszy był mój preferencji). Informacja (jak potwierdzono przez OP) podciąg 'aa' pojawia się dwa razy w ciągu 'aaa', a zatem pięć razy:

string="aaabbccaaaaddbb" 

# 1

Zastosowanie String#scan z regex zawierającej dodatnią lookAhead że wygląda na podciągu:

def count_em(string, substring) 
    string.scan(/(?=#{substring})/).count 
end 

count_em(string,"aa") 
#=> 5 

Uwaga:

"aaabbccaaaaddbb".scan(/(?=aa)/) 
    #=> ["", "", "", "", ""] 

Pozytywny lookbehind daje ten sam wynik:

"aaabbccaaaaddbb".scan(/(?<=aa)/) 
    #=> ["", "", "", "", ""] 

# 2

konwertować do tablicy, stosuje Enumerable#each_cons, a następnie dołączyć i liczyć:

def count_em(string, substring) 
    string.each_char.each_cons(substring.size).map(&:join).count(substring) 
end 

count_em(string,"aa") 
    #=> 5 

Mamy:

enum0 = "aaabbccaaaaddbb".each_char 
    #=> #<Enumerator: "aaabbccaaaaddbb":each_char> 

możemy zobaczyć elementy, które będą generowane przez ten moduł wyliczający przez przekształcenie go do tablicy:

enum0.to_a 
    #=> ["a", "a", "a", "b", "b", "c", "c", "a", "a", "a", 
    # "a", "d", "d", "b", "b"] 

enum1 = enum0.each_cons("aa".size) 
    #=> #<Enumerator: #<Enumerator: "aaabbccaaaaddbb":each_char>:each_cons(2)> 

Konwersja enum1 do tablicy, aby zobaczyć, jakie wartości moduł wyliczający przejdzie do map:

enum1.to_a 
    #=> [["a", "a"], ["a", "a"], ["a", "b"], ["b", "b"], ["b", "c"], 
    # ["c", "c"], ["c", "a"], ["a", "a"], ["a", "a"], ["a", "a"], 
    # ["a", "d"], ["d", "d"], ["d", "b"], ["b", "b"]] 

c = enum1.map(&:join) 
    #=> ["aa", "aa", "ab", "bb", "bc", "cc", "ca", 
    # "aa", "aa", "aa", "ad", "dd", "db", "bb"] 
c.count("aa") 
    #=> 5 
15

Dzieje się tak, ponieważ count liczy się znaków, a nie wystąpień ciągów. W tym przypadku 'aa' oznacza to samo, co 'a', jest uważany za zestaw znaków do zliczenia.

Aby policzyć liczbę razy aa pojawia się w ciągu:

string = "aabbccddbb" 
string.scan(/aa/).length 
# => 1 
string.scan(/bb/).length 
# => 2 
string.scan(/ff/).length 
# => 0 
+0

Widzę, że aby znaleźć liczbę rzeczywistych ciągów znaków, należy użyć metody skanowania zamiast metody liczenia. Dziękuję Ci. – Johnson

+1

Tak {'scan'] (http://www.ruby-doc.org/core-2.1.2/String.html#method-i-scan) przyjmuje wyrażenie regularne, takie jak'/aa/'lub nawet ciąg znaków jak '' aa "' jeśli wolisz i zwraca mecze. 'length' informuje o liczbie dopasowań, jeśli nie obchodzi cię, jakie są dopasowania. – tadman

+0

Możesz także użyć liczby lub rozmiaru zamiast długości. – Johnson

Powiązane problemy