Ошибка кодирования Ruby Run-length

Я новичок, тренирующийся в codewars, и я не могу найти, где моя ошибка в этой задаче RLE, вот инструкции:

Ваша задача — написать такое кодирование длин серий. Для заданной строки верните список (или массив) пар (или массивов) [ (i1, s1), (i2, s2), …, (in, sn)], чтобы можно было восстановить исходную строку путем репликации символ sx ix раз и объединение всех этих строк. Ваша длина кодирования должна быть минимальной, т.е. для всех i значения si и si+1 должны различаться.

Примеры

>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']]

И вот мой код:

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

Я получаю эту ошибку:

`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  `
'

Кодирование длин серий (RLE) — это очень простая форма сжатия данных, при которой ряды данных (то есть последовательности, в которых одно и то же значение данных встречается во многих последовательных элементах данных) сохраняются как одно значение данных и подсчитываются, а не как исходный пробег. Википедия


person Guillermo García Serrano    schedule 21.08.2015    source источник
comment
Вы неправильно используете map!? Целью map является преобразование каждого элемента массива в другой массив с тем же количеством элементов, которое определяется блоком, переданным map. И map! заменяет каждый элемент исходного массива как таковой напрямую.   -  person lurker    schedule 21.08.2015
comment
@lurker Я действительно не знаю. Я думал, что если я хочу изменить массив на месте (обновив количество этого символа только при необходимости), мне придется использовать map!. Спасибо за быстрый ответ :)   -  person Guillermo García Serrano    schedule 21.08.2015
comment
У вас есть break в середине вашего блока map, что является хорошим признаком того, что вы используете его неправильно. Больше похоже на то, что вы пытаетесь использовать его для перебора элементов массива, чтобы изменить другую переменную, что можно сделать с помощью чего-то вроде each.   -  person lurker    schedule 21.08.2015
comment
@lurker О, теперь я понимаю. Еще раз спасибо за вашу помощь.   -  person Guillermo García Serrano    schedule 21.08.2015
comment
Почему вам нужно сначала разбить исходную строку на слова, разделенные пробелами? Основываясь на результатах, которые вы хотите получить в качестве примеров, кажется, что разбиение на слова не имеет значения. Вы считаете пробелы в своем RLE так же, как и другие символы.   -  person lurker    schedule 21.08.2015
comment
Да, ты прав @lurker. Я не сделал хорошую работу, полностью разобравшись с инструкциями. Я рад, что это не был тест в колледже или что-то в этом роде, лол, катастрофические результаты.   -  person Guillermo García Serrano    schedule 22.08.2015


Ответы (2)


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

Здесь мы проверяем последний символ (memo.last.last) и, если он совпадает с текущим, увеличиваем счетчик. В противном случае мы добавляем новый массив в список.

person Aleksei Matiushkin    schedule 21.08.2015
comment
Спасибо @mudasobwa за быстрый ответ! Мне придется подумать над этим кодом :) В любом случае, вы можете найти, где моя ошибка? Даже если это не самый умный или самый эффективный код. - person Guillermo García Serrano; 21.08.2015
comment
В двух словах не могу: в коде много ошибок. Вы даже решаете другую задачу: вы пытаетесь найти существующий элемент, а в задаче четко указано, что вы должны проверять только последний (см. l в желаемом выводе: он появляется дважды). - person Aleksei Matiushkin; 21.08.2015
comment
Хорошо @mudasobwa. Еще раз спасибо за ваше время :) - person Guillermo García Serrano; 21.08.2015

Кодирование длин серий

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
person Arjun    schedule 30.11.2018
comment
Это не берет на себя полную возможность случаев в аккаунте. Попробуйте что-то вроде этого wwwawwwwwbwwww, потом вы не сможете правильно его расшифровать. - person konung; 16.02.2019