繁体   English   中英

交换元组列表中的两个元素

[英]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)]

我假设我们谈论的是这样的事情:
木块拼图 - 滑动拼图 9

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM