在列表中找到元素的前一个元素(Haskell)

Glo*_*ash 2 haskell list

我想返回列表中元素的前一个元素.我打算获取参数索引并使用它来弃用列表,使得参数是最后一个元素,然后反转它并获取反向列表的第二个元素.我得到的错误:类型elemIndexMaybe Int同时take功能要求Int.我想修复它或使用简单的递归编写代码是否有使用递归的较短代码?

precedingElement :: Eq a => a -> [a] -> Maybe a
precedingElement elt lst    | lst == [] = error "List is empty"
                            | elt `notElem` lst = Nothing
                            | otherwise = Just x where x = snd (reverse (take (elt `elemIndex` lst) lst))
Run Code Online (Sandbox Code Playgroud)

pig*_*ker 9

我最喜欢的一个被低估的实用程序对于这样的问题非常方便.让我有一个落后的名单,所以我不需要扭转我的大脑.

data Bwd x = B0 | Bwd x :< x  -- rightmost is nearest
Run Code Online (Sandbox Code Playgroud)

将列表元素视为算盘线上的珠子.向左轻拂几下,然后将手指放在下一个上.你有什么?手指左侧的珠子列表(最右侧最近),手指右侧的珠子列表(最左侧最近),手指放在珠子上.

也就是说,列表的单孔元素上下文由孔的任一侧的一对向后和向前列表给出.

type ListContext x = (Bwd x, [x])
Run Code Online (Sandbox Code Playgroud)

这些谁知道我的老歌承认ListContext作为衍生[].

焦点元素(你的手指在珠子上)是

type ListFocus x = (ListContext x, x)
Run Code Online (Sandbox Code Playgroud)

并且有一个有用的操作,用它的上下文装饰每个列表元素,使它成为焦点.

focus :: [x] -> [ListFocus x]
focus = go B0 where
  go xz [] = []
  go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
Run Code Online (Sandbox Code Playgroud)

例如,

focus [1,2,3] = [((B0,[2,3]),1), ((B0 :< 1,[3]),2), ((B0 :< 1 :< 2,[]),3)]
Run Code Online (Sandbox Code Playgroud)

现在很容易回答涉及元素及其周围环境的各种问题.你可能focus不仅仅是为了解决这个问题而构建,但它是我保留的那种东西,因为它解决了很多问题.

[p | ((_ :< p,_),q) <- focus xs, q == x]
Run Code Online (Sandbox Code Playgroud)

计算p位于xin 左侧的所有值xs.如你看到的.

(顺便说一下,这个focus操作并非来自任何地方.它来自列表数据类型的差异结构.这个答案(在它被称为picks)中更详细地讲述了列表故事,这个答案开发了数据类型的通用故事.)


Cod*_*ice 5

为了返回给定元素的前一个元素,可以使用一些模式匹配和递归:

precedingElement _ [] = Nothing
precedingElement _ [x] = Nothing
precedingElement elt (x:y:rest)
    | y == elt = Just x
    | otherwise = precedingElement elt (y:rest)
Run Code Online (Sandbox Code Playgroud)

  • 考虑`precedingElement elt xs = lookup elt(zip(drop 1 xs)xs)`。 (3认同)
  • 如果将(x:y:rest)放在首位,则第二个(也是最后一个)只不过是precedingElement _ _ = Nothing。 (2认同)