1

https://stepik.org/lesson/Base-RLE-encode-21299/step/2?adaptive=true&unit=5100

На вход алгоритму подаётся строка, содержащая символы латинского алфавита. Эта строка разбивается на группы одинаковых символов, идущих подряд ("серии"). Каждая серия характеризуется повторяющимся символом и количеством повторений. Именно эта информация и записывается в код: сначала пишется длина серии повторяющихся символов, затем сам символ. У серий длиной в один символ количество повторений будем опускать.

Например, рассмотрим строку

aaabccccCCaB

Разобъём её на серии

aaa b cccc CC a B

После чего закодируем серии и получим итоговую строку, которую и будем считать результатом работы алгоритма.

3ab4c2CaB

Формат ввода: Одна строка, содержащая произвольные символы латинского алфавита.

Формат вывода: Строка, содержащая закодированную последовательность.

Sample Input 1: aaabccccCCaB Sample Output 1: 3ab4c2CaB

Вот такая задача. Сейчас код в ужасном состоянии, так как ставил-убирал костыли, ибо не могу понять, в чем ошибка. Я уже самым банальным образом явно указал про длину строки ввода и удалил единицы.

vvod = 'aaabccccCCaB' #input()
if len(vvod) > 1:
    count = 1
    prev = ''
    lst = []
    for i in vvod:
        if i != prev:
            if prev:
                entry = ''
                entry = str(count) + prev
                lst.append(entry)
            count = 1
            prev = i
        else:
                count += 1
    else:
        entry = str(count) + i
        lst.append(entry)
    edinici = ''.join(lst)
    x = ''
    for i in edinici:
        if i != '1':
            x = x + i
    print(x)
else:
    print(vvod)

Очень прошу помочь с задачей, и я, пожалуй, поищу другой задачник.

Не проходит тесты на сайте. Четких объяснений нет, выдает Wrong answer. Интерпретатор выводит все верно—я вводил Sample input из задачи и произвольные строки сам писал.

Failed test #6. Wrong answer
jfs
  • 52,361

1 Answers1

3

Для такой задачи удобно использовать функцию itertools.groupby(), которая группирует соседние одинаковые элементы:

import itertools

def compress(text):
    for char, same in itertools.groupby(text):
        count = sum(1 for _ in same) # number of repetitions
        yield char if count == 1 else str(count)+char

Пример:

>>> ''.join(compress("aaabccccCCaB"))
'3ab4c2CaB'

Чтобы найти ошибку в своём коде, составьте явные тесты и упростите его:

#!/usr/bin/env python3
import unittest

def rle_encode(text):
    result = []
    text += '\0' # dummy
    last = text[0]
    count = 1
    for char in text[1:]:
        if char != last:
            result.append(last if count == 1 else str(count)+last)
            last = char
            count = 0
        count += 1
    return ''.join(result)

class RLETests(unittest.TestCase):
    def test_edges(self):
        self.assertEqual(rle_encode(''), '') # empty
        self.assertEqual(rle_encode('a'), 'a') # one
        self.assertEqual(rle_encode('aa'), '2a') # two
        self.assertEqual(rle_encode('aab'), '2ab') # two + one
        self.assertEqual(rle_encode('abb'), 'a2b') # one + two
        self.assertEqual(rle_encode('aabb'), '2a2b') # two + two

    def test_nonletter(self):
        self.assertEqual(rle_encode('ab b'), 'ab b')
        self.assertEqual(rle_encode('abb\0\0'), 'a2b')

    def test_input(self):
        self.assertEqual(rle_encode('aaabccccCCaB'), '3ab4c2CaB')

Можно перебрать все возможные строки до определённой длины, содержащих не более указанных букв:

    def test_exhaustive(self):
        for r in range(6):
            for text in map(''.join, itertools.product('abcAB', repeat=r)):
                with self.subTest(text=text):
                    self.assertEqual(rle_groupby(text), rle_encode(text))


if __name__ == '__main__':
    unittest.main()

где:

def rle_groupby(text):
    return ''.join([char if count == 1 else str(count)+char
                    for char, same in itertools.groupby(text)
                    for count in [sum(1 for _ in same)]])
jfs
  • 52,361
  • не проходило тесты, хотя на всех вводимых мной вручную строках интерпретатор отвечал верно. Я нажал вам плюс, но, к сожалению, не хватает репутации пока. Про функцию эту не знал, очень полезная, спасибо. – Emil Aliyev Nov 23 '16 at 23:37
  • Сделал. Как видите, я еще новичок, и написать работающий код для меня уже само по себе достижение, поэтому, когда появляются непонятные ошибки, я просто не знаю, что делать. – Emil Aliyev Nov 24 '16 at 00:02
  • @EmilAliyev: добавил реализацияю без groupby() и тесты. – jfs Nov 24 '16 at 00:29
  • и ваш и мой коды успешно проходят тесты. Внимательно прочитал комментарии к задаче. Вероятнее всего, проблема была в моем методе вычеркивания единиц, так как я просто собирал новую строку из результата, ибо мой результат выглядел как 3a1b4c2C1a1B . Видимо, тесты чувствительны к этому. – Emil Aliyev Nov 24 '16 at 01:13
  • @EmilAliyev: единицы не могут быть в результате по условию задачи. Вы уверены, что вы правильно тесты запускали? test_nonletter() говорит как моя реализация работает на вводе, который не может подаваться по условиям задачи (разные реализации могут здесь всё что угодно делать, хоть exception выбрасывать). Ваша реализация не должна была этот тест пройти. – jfs Nov 24 '16 at 01:18
  • сделал еще раз. моя реализация не проходит тест test_nonletter AssertionError: 'a2b2\x00' != 'a2b' – Emil Aliyev Nov 24 '16 at 01:36
  • @EmilAliyev это ожидаемо. А на сайте проходит? Можно ещё попробовать все возможные строки до определённой длины, содержащих не более указанных букв проверить. К примеру от нуля до пяти длина с пятью буквами или меньше. (itertools.product("abcde", repeat=r) for r in range(5)) может помочь ввод сгенерировать, а для проверки сравнивать результаты трёх функций. Привести явный код для такого теста или сами попробуете? – jfs Nov 24 '16 at 01:48
  • Дело в том, что сайт не сообщает подробностей ошибки. Лишь порядковый номер теста. Можете немного подробнее сказать, как это сделать? Я хочу сам понять, но, боюсь, несколько сложно мне это будет сделать. – Emil Aliyev Nov 24 '16 at 01:54
  • @EmilAliyev: достаточно знать проходят или нет на сайте. Вы уверено, что дело не в формате? (новая строка, пробел?) Я добавил тесты "полным перебором". Если тесты "полным перебором" проходят для вашего кода, то попробуйте его упростить (перезапуская тесты после каждого изменения—запускайте тесты в не более чем один аккорд клавиатурный) Цель улучшить понимание, что ваш код делает. Используйте git или hg, чтобы не бояться изменения делать, чтобы можно было откатиться если потеряетесь в ваших изменениях. – jfs Nov 24 '16 at 02:14