2013-11-14 1 views
3

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

Это то, что я хочу:

word("aaabbcbbaaa") == [["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]] 
word("aaaaaaaaaa") == [["a", 10]] 
word("") == [] 

Вот мой код:

def word(str) 
words=str.split("") 
count = Hash.new(0) 

words.map {|char| count[char] +=1 } 

return count 
end 

Я получил слово ("aaabbcbbaaa") => [[ "а", 6], [» b ", 4], [" c ", 1]], чего я не хочу. Я хочу считать каждую последовательность. Я предпочитаю не использовать регулярное выражение. Благодарю.

+1

вопрос помечается как регулярное выражение, но название говорит не с помощью регулярных выражений. Который из них? – jaco0646

+0

обновил теги – hken27

+0

+1 для интересных умственных упражнений, хотя я думаю, что регулярное выражение - это путь. –

ответ

6

Разбивает строку по гольцов, затем группа ломти по полукокса, а затем подсчитывать символы в кусках:

def word str 
    str 
    .chars 
    .chunk{ |e| e } 
    .map{|(e,ar)| [e, ar.length] } 
end 

p word "aaabbcbbaaa" 
p word("aaaaaaaaaa") 
p word "" 

Результат:

[["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]] 
[["a", 10]] 
[] 
+0

Никогда не замечал 'chunk' раньше. Это довольно круто – MxyL

+0

Очень красивый Евгений, люблю ваш ответ. #chunk - хороший метод для использования. Спасите массу неприятностей. – hken27

+0

Ницца, Евгений. '.chunk: _alone' также работает. –

0

Вы можете использовать этот шаблон с разверткой:

"aaabbcbbaaa".scan(/((.)\2*)/) 

и после подсчета количества полукокса для всей группы 1

пример:

"aaabbcbbaaaa".scan(/((.)\2*)/).map do |x,y| [y, x.length] end 
+0

Это связано с регулярным выражением. – MxyL

+0

спасибо Казимир. Я посмотрел на использование вашего регулярного выражения. Попытка выяснить, могу ли я решить проблему без использования регулярного выражения. Очень хороший фрагмент кода.:) – hken27

+0

@ hken27 Вы не пытаетесь понять, можете ли вы его решить, вы пытаетесь выяснить, решает ли кто-нибудь его для вас. Почему вы не можете использовать регулярное выражение? – sawa

2

Если вы не хотите используйте регулярное выражение, вы можете просто сделать что-то вроде:

def word(str) 
    last, n, result = str.chars.first, 0, [] 
    str.chars.each do |char| 
    if char != last 
     result << [last, n] 
     last, n = char, 1 
    else 
     n += 1 
    end 
    end 
    result << [last, n] 
end 

Я хотел бы использовать некоторую функцию более высокого порядка, чтобы сделать ее более кратким, но в стандартной библиотеке Ruby нет соответствующей. Enumerable#partition почти не работает, но не совсем.

+0

Это не работает для меня - все дает мне [[nil, str.length]] ' –

+0

@ KenY-N: ОК, исправлена ​​ошибка. –

1

Я бы сделал следующее. Обратите внимание, что each_char - это более новый метод (Ruby 1.9?), Который может быть недоступен в вашей версии, поэтому придерживайтесь в этом случае words=str.split("").

def word(str) 
    return [] if str.length == 0 
    seq_count = [] 
    last_char = nil 
    count = 0 
    str.each_char do |char| 
    if last_char == char 
     count += 1 
    else 
     seq_count << [last_char, count] unless last_char.nil? 
     count = 1 
    end 
    last_char = char 
    end 
    seq_count << [last_char, count] 
end 

[52] pry(main)> word("hello") 
=> [["h", 1], ["e", 1], ["l", 2], ["o", 1]] 

[54] pry(main)> word("aaabbcbbaaa") 
=> [["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]] 

[57] pry(main)> word("") 
=> [] 
+1

Я думал по этой же линии, но мне было трудно реализовать ее. Вышеупомянутое решение Еева очень хорошее. Ruby имеет так много методов и способов решения вещей. Это слишком много, чтобы учиться. Я очень доволен сообществом людей, имеющих опыт, который они готовы поделиться. спасибо за вашу работу – hken27

+0

Я согласен - хотя его конкатенаты, возможно, не известны методы, это кратким и комментарий может прояснить ситуацию. Мой код выше имеет два особых случая и множество путей управления. Если вы не имеете дело с миллионами длин длинными символами, дополнительное распределение памяти не должно быть проблемой, и его решение может быть даже быстрее, поскольку, возможно, методы реализованы в C? –

1

еще один не регулярное выражение-версии.

x = "aaabbcbbaaa" 

def word(str) 
    str.squeeze.reverse.chars.each_with_object([]) do |char, list| 
    count = 0 
    count += 1 until str.chomp!(char).nil? 
    list << [char, count] 
    end 
end 

p word(x) #=> [["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]] 
1

Если бы мир был без regex и chunk:

def word(str) 
    a = str.chars 
    b = [] 
    loop do 
    return b if a.empty? 
    c = a.slice_before {|e| e != a.first}.first 
    b << [c.first, c.size] 
    a = a[c.size..-1]  
    end 
end 

word "aaabbcbbaaa" # => [["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]] 
word "aaa"   # => [["a",3]] 
word ""   # => [] 

Вот еще один способ. Сначала я попытался найти решение, которое не требовало преобразования строки в массив ее символов. Я не мог придумать ничего достойного, пока я не увидел @hirolau ответ «s, который я модифицированную:

def word(str) 
    list = [] 
    char = str[-1] 
    loop do 
    return list if str.empty? 
    count = 0 
    count += 1 until str.chomp!(char).nil? 
    list.unshift [char, count] 
    char = str[-1] 
    end 
end