3

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

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Are you misusing `map!`? The purpose of `map` is to convert each element of the array to another array with the same number of elements which are determined by the block given to `map`. And `map!` replaces each element in the original array as such directly. – lurker Aug 21 '15 at 12:07
  • @lurker I don't really know. I thought that if i wanted to modify the array on place(upgrading the count of that character only if needed) I had to use `map!`. Thank you for your fast answer :) – Guillermo García Serrano Aug 21 '15 at 12:16
  • You have a `break` in the middle of your `map` block, which is a good sign that you're not using it right. Looks more like you're trying to use it to loop through your array elements to modify a different variable, which would be done with something like `each`. – lurker Aug 21 '15 at 12:17
  • @lurker Oh, I understand now. Thank you once again for your help. – Guillermo García Serrano Aug 21 '15 at 14:16
  • Why do you need to split the original string into space-separated words first? Based upon the results you say you want to obtain as examples, it seems that the break into words isn't relevant. You're counting spaces in your RLE just like other characters. – lurker Aug 21 '15 at 14:28
  • Yes, you are right @lurker. I didn't do a good job fully understanding the instructions. I'm glad it was not a college test or whatever lol, disastrous results. – Guillermo García Serrano Aug 21 '15 at 23:27

2 Answers2

1
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.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • Thank you @mudasobwa for your fast answer! I will have to ponder over that code :) Anyway, can you find where my mistake is? Even though it is not the smartest or most efficient code. – Guillermo García Serrano Aug 21 '15 at 12:17
  • I can not do it in a couple of words: the code contains many errors. You are even solving other task: you are trying to lookup the existing element, while the task clearly states that you should check the last one only (see `l` in your desired output: it appears twice.) – Aleksei Matiushkin Aug 21 '15 at 12:37
  • Okay @mudasobwa. Thanks again for your time :) – Guillermo García Serrano Aug 21 '15 at 14:15
-1

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
Arjun
  • 815
  • 1
  • 8
  • 18
  • It doesn't take the full possibility of cases in the account . Try something like this "wwwawwwwwbwwww", you won't be able to properly decode it afterwards. – konung Feb 15 '19 at 21:28