Elm匹配列表关联数据时如何处理find返回的Maybe类型
回答
直接解法:处理Maybe类型完成匹配
你当前逻辑的核心问题是List.Extra.find返回Maybe Drink类型,代表「找到对应饮品」和「没找到对应饮品」两种可能,不需要复杂的分支判断,用List.filterMap就可以一步完成匹配+过滤无效项:
model.selected |> List.filterMap (\selectedItem -> List.Extra.find (\drink -> drink.id == selectedItem.id) model.drinks |> Maybe.map (\matchedDrink -> (selectedItem, matchedDrink)) ) |> List.map itemRow
List.filterMap会自动丢弃返回Nothing的无效项(比如已选列表里的id在饮品列表里已经被删除的异常数据),只保留匹配成功的(Item, Drink)元组,完全匹配你itemRow函数的入参类型。
之后只需要给itemRow加上元组解构即可正常使用:
itemRow : (Item, Drink) -> Html Msg itemRow (item, drink) = tr [ id item.id ] [ td [] [ button [] [ text "x" ] ] , td [] [ text drink.name ] , td [] [ input [ type_ "number", value (String.fromInt item.quantity) ] [] ] ]
更推荐的优化方案:调整数据建模从根源避免问题
当前建模每次渲染都要遍历整个饮品列表做id匹配,时间复杂度为O(n*m),且需要额外处理匹配失败的异常,你可以选以下两种更合理的建模方式:
- 方案1:已选项直接存储完整饮品数据
把选中项的结构调整为直接关联完整的Drink记录,渲染时完全不需要额外查找:
这种写法逻辑最简单,唯一需要注意的是如果后续支持编辑饮品的名称等属性,需要同步更新已选列表里对应项的饮品数据。type alias SelectedItem = { drink: Drink , quantity: Int } type alias Model = { drinks: List Drink , selected: List SelectedItem , inputDrink: String , inputQuantity: Int } - 方案2:预构建字典提升查找效率
如果担心多份数据同步的问题,可以在模型初始化时把饮品列表转换为id为键的字典,把查找时间复杂度降到O(1):
渲染时把原来的import Dict exposing (Dict) type alias Model = { drinks: List Drink , drinksDict: Dict String Drink -- 初始化时通过 Dict.fromList (List.map (\d -> (d.id, d)) drinks) 生成 , selected: List Item , inputDrink: String , inputQuantity: Int }List.Extra.find替换为字典取值即可,性能远高于列表遍历查找,适合饮品列表较长的场景:model.selected |> List.filterMap (\selectedItem -> Dict.get selectedItem.id model.drinksDict |> Maybe.map (\matchedDrink -> (selectedItem, matchedDrink)) ) |> List.map itemRow
内容的提问来源于stack exchange,提问作者iamsim.me
相关产品推荐
相关产品推荐

