在 Elm 中获取列表的下一个元素的最佳方法

mar*_*hro 3 elm

我目前正在尝试找出遍历列表的最佳方法。我说的穿越是什么意思?

例子:

我有一个用户列表:

userList : List User 
userList =
    [user, user, user, user]
Run Code Online (Sandbox Code Playgroud)

我有一个 currentUser,它必须是 userList 之外的用户

所以我想要实现的是:我想要像List.getNext这样的东西,它接受 userList 和当前用户并返回列表中相对于 currentUser 的下一个用户

这是我的实现。我认为这非常复杂 - 那么有人知道如何以更好的方式做到这一点吗?

traverseList : List a -> a -> Maybe (Maybe a)
traverseList list currentElement =
    let
        indexList =
            List.indexedMap
                (\index element ->
                    if element == currentElement then
                        index
                    else
                        -1
                )
                list

        currentAsIndex =
            let
                mayBeIndex =
                    List.maximum indexList
            in
                case mayBeIndex of
                    Just index ->
                        index

                    Nothing ->
                        0

        getWanted =
            List.map
                (\( id, element ) ->
                    if id == (currentAsIndex + 1) then
                        Just element
                    else
                        Nothing
                )
                (List.indexedMap (,) list)
                |> List.filter
                    (\element ->
                        element /= Nothing
                    )
                |> List.head

    in
        getWanted
Run Code Online (Sandbox Code Playgroud)

解释:

我的方法是获取列表,创建给定列表的索引列表(看起来像这样 [-1, -1, -1, 3, -1, -1])

然后我得到这个列表的最大值 - 因为这给了我当前用户在 List.indexedMap 中的位置。

然后我将原始元素作为 List.indexedMap 进行迭代,并找出下一个元素(在我们的例子中为 4 号)并返回该元素。否则我什么也不返回。

然后,我过滤此“无内容列表”和仅一个用户,并使用 List.head 从列表中提取该用户。

结果是一个也许(也许用户)...这不太好...或者?

感谢您提供任何以更好的功能方式做类似事情的想法。

我真的很努力在函数式编程方面做得更好。

sth*_*lzm 5

这是一个非常简单的递归解决方案:

getWanted  : List a -> a -> Maybe a
getWanted list currentElement = 
    let findNextInList l = case l of
        []             -> Nothing
        x :: []        -> if x == currentElement
                          then List.head list
                          else Nothing
        x :: y :: rest -> if x == currentElement
                          then Just y
                          else findNextInList (y :: rest)
    in
        findNextInList list
Run Code Online (Sandbox Code Playgroud)

这里的想法是查看列表的前两个元素,如果第一个是当前元素,则获取第二个。如果没有,请使用列表的尾部重试。

必须处理极端情况(您可以为此函数编写至少 4 个单元测试):

  • 根本找不到当前元素
  • 当前元素是列表中的最后一个元素
  • 该列表可能为空

也许有一个更优雅的解决方案,但递归是函数式编程中非常常见的技术,所以我想分享这种方法。