[英]Swapping two elements in a list of tuples
(这是这个问题的后续问题,其中缺少定义)
试图创建一个 function 可以交换元组列表中的两个元素。 例如,如果我有:
[(NW, Just 1),(N, Just 2),(NE, Just 3),(W, Just 4),(M, Just 5),
(E, Just 6),(SW, Just 7),(S, Just 8),(SE, Nothing)]
我想交换 S 和 SE 的第二个元素以获得
[(NW, Just 1),(N, Just 2),(NE, Just 3),(W, Just 4),(M, Just 5),
(E, Just 6),(SW, Just 7),(S, Nothing),(SE, Just 8)]
我将如何 go 这样做? 我尝试创建一个 function swapper
器,
swapper :: (Eq a, Eq b) => a -> b -> b -> [(a,b)] -> [(a,b)]
swapper x y z ((a,b):xs) | x == a = ((a,z):xs)
| z == b = ((a,y):xs)
| otherwise = swapper x y z xs
但这会返回
[(S,Nothing),(SE,Nothing)]
我可以看到,在找到我的目标状态之一后,我没有存储初始元组或循环。 但是我不确定如何在 Haskell 中执行此操作。
为了在需要时提供更多上下文,function 的四个输入是
(swapper p (label p (Grid b)) (Nothing) b)
在哪里
p = position I want to move to the Nothing space -- (S -> SE)
label p (Grid b) = returns current label of p -- (S = Just 8)
Nothing = passing in Nothing because I was getting errors
when trying to do z == Nothing
b = current board -- ([(NW, Just 1),(N, Just 2),(NE, Just 3),
-- (W, Just 4),(M, Just 5),(E, Just 6),
-- (SW, Just 7),(S, Just 8),(SE, Nothing)])
如何创建一个 function 可以将列表拆分为前任、匹配元素和后继?
splitOn :: (a -> Bool) -> [a] -> ([a], Maybe a, [a])
splitOn predicate xs =
case break predicate xs of
(us, []) -> (us, Nothing, [])
(us, (m:vs)) -> (us, Just m, vs)
> splitOn (== 3) [1..5]
([1,2],Just 3,[4,5])
> splitOn (== 7) [1..5]
([1,2,3,4,5],Nothing,[])
然后你可以拆分、交换和重组:
import Data.Maybe (maybeToList)
swap :: Eq a => a -> a -> [a] -> [a]
swap a b xs =
let (us, m, xs') = splitOn predicate xs
(vs, n, ws) = splitOn predicate xs'
in us ++ (maybeToList n) ++ vs ++ (maybeToList m) ++ ws
where
predicate x = x == a || x == b
> swap 3 4 [1..5]
[1,2,4,3,5]
> swap 7 4 [1..5]
[1,2,3,5,4]
并不是说这个版本假定一个元素最多包含在列表中一次。
交换第一个元素(如果元素包含不止一次)的更新版本是
swap' :: Eq a => a -> a -> [a] -> [a]
swap' a b xs =
let (us, m, xs') = splitOn isFirst xs
(vs, n, ws) = case m of
Nothing -> (xs', Nothing, [])
Just m' -> splitOn (== (other m')) xs'
in us ++ (maybeToList n) ++ vs ++ (maybeToList m) ++ ws
where
isFirst x = x == a || x == b
other x = if x == a then b else a
> swap' 3 4 (3:[1..5])
[4,1,2,3,3,5]
> swap' 7 4 (3:[1..5])
[3,1,2,3,5,4]
> swap' 3 3 (3:[1..5])
[3,1,2,3,4,5]
正如您所写,如果x==a
,您不希望 return ((a,z):xs)
。 您要处理列表的 rest: ((a,z):swapper xyz xs)
。 与z==b
相同。 然后算法以错误结束: Non-exhaustive patterned in function swapper
。 所以我为空列表添加了模式: swapper xyz [] = []
。 然后swapper
只返回列表的一部分。 所以我添加了(a,b):
也在子句的swapper
器之前添加otherwise
。
现在您的算法如下所示:
swapper :: (Eq a, Eq b) => a -> b -> b -> [(a,b)] -> [(a,b)]
swapper x y z ((a,b):xs) | x == a = ((a,z):swapper x y z xs)
| z == b = ((a,y):swapper x y z xs)
| otherwise = (a,b):swapper x y z xs
swapper x y z [] = []
并按预期返回列表:
[(NW,Just 1),(N,Just 2),(NE,Just 3),(W,Just 4),
(M,Just 5),(E,Just 6),(SW,Just 7),(S,Nothing),(SE,Just 8)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.