我最近开始学习Haskell。我试图反转包含字符和数字的字符串。该字符串将被反转,保持原始位置的数字。
Original String =“H1AW2J1”
反转= J1WA2H1
我试图遵循我在Swift中使用的模式。
以下是按照上述步骤操作的代码。
reversChars“H1AW2J1”重新调整“JWAH”
reversedChars = reverse . filter isLetter
索引返回元组。
indexes xs = [(x, elemIndex x xs) | x <- xs]
[('H',Just 0),('1',Just 1),('A',Just 2),('W',Just 3),('2',Just 4),( 'J',Just 5),('1',Just 1)]
问题
reversedChars
elemIndex
返回相同的索引Just 1
,多次出现1。答案 0 :(得分:5)
- 如何将相应索引处的数字插入
醇>reversedChars
我会使用这样的递归函数,如果它遇到一个字母,会插入下一个反向字符,否则只插入实际字符:
import Data.Char
reverseLetters :: String -> String
reverseLetters xs = go xs (reverse $ filter isLetter $ xs)
where
go xs [] = xs
go (x:xs) (r:rs) | isLetter x = r : go xs rs
| otherwise = x : go xs (r:rs)
main = print $ reverseLetters "H1AW2J1"
输出:
"J1WA2H1"
- 醇>
elemIndex
返回相同的索引Just 1
,多次出现1。
那是因为这是elemIndex
定义返回的内容。如果你想要所有指数,你可以这样做:
Prelude> map fst $ filter ((== '1') . snd) $ zip [0..] "H1AW2J1"
[1,6]
答案 1 :(得分:2)
我的解决方案看起来也类似于@ Dogbert,但是这个解决问题的方式实现了它。
标准库中的列表没有update
函数,即使有,也不是一个好主意,因为它会有O(n),其中n是索引,因为列表是单链表。相反,你必须编写自己的函数来将数字包含在字符串中:
reverseChars :: [Char] -> [Char]
reverseChars cs = insert reversedChars digits
where reversedChars = reverse $ filter isLetter cs
digits = filter (\(_,c) -> isDigit c) $ indexes cs
insert :: [a] -> [(Int, a)] -> [a]
insert = go 0
where go i (x:xs) ((j,y):ys)
| j > i = x : go (i+1) xs ((j,y):ys)
| otherwise = y : go (i+1) (x:xs) ys
go _ xs [] = xs
go _ [] ys = map snd ys
indexes :: [a] -> [(Int, a)]
indexes = zip [0..]
我也改变了索引的实现,因为elemIndex
也有复杂度O(n),n是列表中搜索元素的位置,所以你的索引函数会有O(n²) 。此外,通过此实现,您可以摆脱Maybe
中的indexes
。
答案 2 :(得分:0)
不同的方法不需要找到单个元素的索引:
reverseIf :: (a -> Bool) -> [a] -> [a]
reverseIf f = fill <*> reverse . filter f
where fill s [] = s
fill (s:ss) (r:rs)
| f s = x : fill ss rs
| otherwise = s : fill ss (r:rs)
这是另一个版本:
reverseIf :: (a -> Bool) -> [a] -> [a]
reverseIf f = snd . (flip (mapAccumL g) <*> reverse . filter f)
where g r e | f e = (tail r, head r)
| otherwise = (r, e)
调用:
> reverseIf (not . isDigit) "H1AW2J1"
"J1WA2H1"