Манипулирование строк в Haskell - PullRequest
3 голосов
/ 06 апреля 2019

Я пытаюсь создать функцию, которая объединяет строки с учетом списка целых чисел. Например, скажем, функции было присвоено [1,2,3], тогда результат будет " ***". По сути, каждое число представляет собой * с пробелами перед ним. Таким образом, число 5 будет " *", то есть 4 пробела, за которыми следует *. Тем не менее, мне дали список, и я не могу просто ++ их всех вместе, потому что строки портят порядок.

Моя идея состояла в том, чтобы начать с первого элемента в списке и рекурсивно отправить его обратно в виде строки. Поэтому для [1,2,3] я бы отправил обратно в функцию [2,3] с String = " *". Далее, для каждого элемента я проверяю, равна ли длина строки -1 <= следующему элементу (- 1, потому что 0 включено). В списке, который я даю функции, это всегда будет иметь место (список всегда будет числом от 0 до 9, увеличиваясь, и НЕТ повторений). Затем я бы ++ снова отправил исходную строку в вызов функции, чтобы сделать рекурсивное утверждение. Я делал это, пока ничего не осталось. Вот что я сделал:

makeStr :: [Integer] -> String -> String
makeStr [] _ = ""
makeStr (x:xs) s
        | null xs && s == ""               = getStar ((fromIntegral x)) "*"
        | null xs && s /= ""               = s ++ getStar ((fromIntegral x) - (length s)) "*"
        | s == ""                          = makeStr xs (getStar ((fromIntegral x) - ((length s))) "*")
        | length s - 1 <= (fromIntegral x) = s ++ makeStr xs (getStar ((fromIntegral x) - ((length s))) "*")

Примечание: getStar - это простая функция, которая принимает число и «*» и возвращает строку с правильным количеством пробелов. Он имеет декларацию getStar :: Int -> String -> String. Эта функция работает отлично, я тестировал ее много раз, и я действительно не верю, что это проблема, поэтому я не включил ее.

Пример функции getStar:

getStar 3 "*"
"   *"

некоторые примеры входов с ожидаемыми выходами:

makeStr [1,2,3] ""
" ***"

makeStr [0,2,3] ""
"*  **"

makeStr [1,2,3,4] ""
" ****"

makeStr [0,9] ""
"*        *"

Вывод моей программы некорректен для любого списка из 2 элементов.

makeStr [0,1] "" -- correct
"**"

makeStr [1,2,3] "" -- incorrect, should be " ***"
" **  *"

makeStr [1,2,3,4] "" -- incorrect, should be " ****"
" **  * *"

Я не могу понять, почему это правильно для первых двух элементов, а затем для чего-то неправильного после. Я проследил это несколько раз, но кажется, что все должно работать нормально.

Редактировать Решение:

makeStr :: [Integer] -> String
makeStr [] = ""
makeStr (x:xs)
            | x == 0 = "*" ++ makeStr (map (subtract 1) xs)
            | x /= 0 = " " ++ makeStr (map (subtract 1) (x:xs))

Ответы [ 2 ]

5 голосов
/ 06 апреля 2019

Возможное решение может быть следующим:

  • Если список ввода пуст, вернуть пустую строку.
  • Если список ввода x:xs, отметьте x.
    • Если x==0, тогда сгенерировать '*', и повторить с xs, где каждое число было уменьшено
    • Если x/=0, тогда сгенерировать ' ' и рекурсироватьс x:xs, где каждое число было уменьшено

Например

f [1,3]
= ' ' : f [0,2]
= ' ' : '*' : f [1]
= ' ' : '*' : ' ' : f [0]
= ' ' : '*' : ' ' : '*' : f []
= ' ' : '*' : ' ' : '*' : []
= " * *"

Вышеуказанное неэффективно, как могло бы быть.Можно повысить эффективность, сохраняя второй целочисленный аргумент «offset» и увеличивая его вместо уменьшения целого списка.

2 голосов
/ 06 апреля 2019

@ Чи решение, но без необходимости уменьшать каждый элемент списка на каждом рекурсивном шаге.

makeStr = f 0

f _ [] = ""
f i (x:xs)
    | x - i == 0 = '*' : f (i+1) xs
    | otherwise  = ' ' : f (i+1) (x:xs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...