Need help with this code on counting chars in a sequence.
This is what I want:
word("aaabbcbbaaa") == [["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]]
word("aaaaaaaaaa") == [["a", 10]]
word("") == []
Here is my code:
def word(str)
words=str.split("")
count = Hash.new(0)
words.map {|char| count[char] +=1 }
return count
end
I got word("aaabbcbbaaa") => [["a", 6], ["b", 4], ["c", 1]], which is not what I want. I want to count each sequence. I prefer a none regex solution. Thanks.
Split string by chars, then group chunks by char, then count chars in chunks:
def word str
str
.chars
.chunk{ |e| e }
.map{|(e,ar)| [e, ar.length] }
end
p word "aaabbcbbaaa"
p word("aaaaaaaaaa")
p word ""
Result:
[["a", 3], ["b", 2], ["c", 1], ["b", 2], ["a", 3]]
[["a", 10]]
[]
If you don't want to use a regex, you may just have to do something like:
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
I'd like to use some higher-order function to make this more concise, but there's no appropriate one in the Ruby standard library. Enumerable#partition
almost does it, but not quite.
I'd do the following. Note that each_char
is a newer method (Ruby 1.9?) that might not be available on your version, so stick with words=str.split("")
in that case.
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("")
=> []
Another non-regexp-version.
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]]
If the world were without regex
and 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 "" # => []
Here's another way. Initially I tried to find a solution that didn't require conversion of the string to an array of its characters. I couldn't come up with anything decent until I saw @hirolau 's answer, which I modified:
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
You can use this pattern with scan:
"aaabbcbbaaa".scan(/((.)\2*)/)
and after count the number of char for all group 1
example:
"aaabbcbbaaaa".scan(/((.)\2*)/).map do |x,y| [y, x.length] end
来源:https://stackoverflow.com/questions/19969066/ruby-counting-chars-in-a-sequence-not-using-regex