Ruby Run-length encoding fail

I'm a newbie training at codewars and I can't find where my mistake is in this RLE problem , here are the instructions:

Your task is to write such a run-length encoding. For a given string, return a list (or array) of pairs (or arrays) [ (i1, s1), (i2, s2), …, (in, sn) ], such that one can reconstruct the original string by replicating the character sx ix times and concatening all those strings. Your run-length encoding should be minimal, ie. for all i the values si and si+1 should differ.

Examples

>rle("hello world!")
# => [[1,'h'],[1,'e'],[2,'l'],[1,'o'],[1,' '],[1,'w'],[1,'o'],[1,'r'],[1,'l'],[1,'d'],[1,'!']]

>rle("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb")
# => [[34,'a'], [3,'b']]

And here is my code:

def rle(str)
  result=[[]]
  str.to_s.split.each do |word| #"Hello World"->["Hello","World!"]-->"Hello", "World!"
    new_word_count=[[]]
    word.each_char do |char| #"H","e","l"...
      new_char=true
      new_word_count.map! do |find|
        if find[1]==char
        find[0]+=1
        new_char=false
        break
        end
      end
      if new_char==true
        new_word_count<<[1,'char']
      end
    end
    result+=new_word_count
  end
  result
end

I get this error:

`block (3 levels) in rle': undefined method `[]' for nil:NilClass (NoMethodError)
from `map!'
from  `block (2 levels) in rle'
from  `each_char'
from  `block in rle'
from  `each'
from  `rle'
from  `
'

Run-length encoding (RLE) is a very simple form of data compression in which runs of data (that is, sequences in which the same data value occurs in many consecutive data elements) are stored as a single data value and count, rather than as the original run. Wikipedia

Upvotes: 3

Views: 1526

Answers (2)

Arjun
Arjun

Reputation: 823

Run length Encoding

str = wwwwaaadexxxxxx # After encoding w4a3d1e1x6
h = {} 
str.split("").map{|e| h[e].nil? ? h[e] = 1 : h[e] +=1}
h.to_a.flatten.join # w4a3d1e1x6

Upvotes: -1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

def rle s
  s.each_char.inject([]) do |memo, c| 
     memo.last && c == memo.last.last ? memo.last[0] += 1 : memo << [1, c]
     memo
  end
end

Here we check for the last char (memo.last.last) and if it the same as current, we increase counter. Otherwise we add new array to the list.

Upvotes: 1

Related Questions