繁体   English   中英

将列表中的相邻元素放入元组

[英]Put adjacent elements in List into Tuples

给定元素列表:

xs = [a, b, c, d, ... z]

其中a, b, c等是任意值的占位符。 我想实现一个adjacents :: [a] -> [(a, a)]的函数adjacents :: [a] -> [(a, a)]产生

adjacentValues = [(a, b), (b, c), (c, d), ... (y, z)]

在Haskell中,递归定义相当简洁:

adjacents :: [a] -> [(a, a)]
adjacents (x:xs) = (x, head xs) : adjacents xs
adjacents [] = []

Purescript有点冗长:

adjacents :: forall a. List a -> List (Tuple a a)
adjacents list = case uncons list of 
    Nothing -> []
    Just {head: x, tail: xs} -> case head xs of
                                     Just next -> Tuple x next : adjacents xs
                                     Nothing -> []

有没有一种方法可以表达adjacents而不显式递归(使用折叠)?


免责声明:这个问题同时具有Purescript和Haskell标签,因为我想向更多的读者开放。 我认为答案不取决于haskells惰性评估语义,因此在两种语言中均有效。

在Haskell中,无需显式递归,您可以使用尾部压缩列表。

   let a = [1,2,3,4,5,6,7,8,9,0]

   a `zip` tail a

   => [(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,0)]

为了完整起见,Purescript解决方案:

adjacent :: forall n. List n -> List (Tuple n n)
adjacent list = zip list $ fromMaybe empty $ tail list

可以更优雅地表示为:

adjacent :: forall n. List n -> List (Tuple n n)
adjacent list = zip list $ drop 1 list

为了便于说明(基于zip的解决方案绝对更好),这是您编写的显式递归Haskell解决方案,以实现形式展示。 我没有特别的理由将它打成单线。

{-# LANGUAGE LambdaCase #-}

import Data.List (unfoldr)

adjacent :: [a] -> [(a, a)]
adjacent = unfoldr (\case { x:y:ys -> Just ((x, y), ys); _ -> Nothing })

(请注意,这里的模式匹配具有奇数个元素的句柄列表,而不会崩溃。)

既然我们已经看过zipunfoldr ,那么我们应该使用foldr

adjacent :: [a] -> [(a,a)]
adjacent xs = foldr go (const []) xs Nothing
  where
    go a r Nothing = r (Just a)
    go a r (Just prev) = (prev, a) : r (Just a)

现在,由于每个玩具问题都应得到过度设计的解决方案,因此可以使用以下方法来进行双面列表融合:

import GHC.Exts (build)

adjacent :: [a] -> [(a,a)]
adjacent xs = build $ \c nil ->
  let
    go a r Nothing = r (Just a)
    go a r (Just prev) = (prev, a) `c` r (Just a)
  in foldr go (const nil) xs Nothing
{-# INLINE adjacent #-}

与状态折叠,其中状态是最后配对的项:

在Haskell:

import Data.List (mapAccumL)

adjacents :: [a] -> [(a, a)]
adjacents [] = []
adjacents (x:xs) = snd $ mapAccumL op x xs
    where
        op x y = (y, (x,y))

暂无
暂无

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

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