首页 > 解决方案 > F# List split,divide

问题描述

我正在尝试在 F# 中解决一个练习。我必须编写一个可以区分书和电影的代码,并将其作为书或电影放在列表中。它可以通过文件大小区分两者,因为书籍没有文件大小。例如,如果我放入一本书,代码必须将它作为一本书添加到列表中,并且对于电影也是如此。我将示例结果和输入链接起来。先感谢您。

type Movie =
    { movieName: string
      duration: Nat
      fileSize: Nat }

type Book =
    { bookName: string
      pages: Nat }

type Activity =
    | Watch of Movie
    | Read of Book


let rec createActivities(hl: (string * Nat * Nat) list): Activity list = 
    match hl with
      | [] -> []
      | x::xs -> ....

以下是输入:

createActivities([
                "The Hobbit"                , 304N, 0N
                "The Fellowship of the Ring", 228N, 50N
                "The Name of the Wind"      , 662N, 0N
                "The Emoji Movie"           , 86N , 1024N
                "The Hobbit"                , 164N, 9001N
                "The Fellowship of the Ring", 700N, 0N

结果:

[
                Read { bookName = "The Hobbit"; pages = 304N }
                Watch { movieName = "The Fellowship of the Ring"; duration = 228N; fileSize = 50N }
                Read { bookName = "The Name of the Wind"; pages = 662N }
                Watch { movieName = "The Emoji Movie"; duration = 86N; fileSize = 1024N }
                Watch { movieName = "The Hobbit"; duration = 164N; fileSize = 9001N }
                Read { bookName = "The Fellowship of the Ring"; pages = 700N }
            ]

标签: listsplitf#divide

解决方案


F# 中的匹配表达式可以非常先进,在匹配表达式的各个部分中都有子匹配。例如,x::xs匹配表达式中的大小写可以转换为(name, duration, filesize) :: xs. 如果您为其中一个指定一个值,那么它只会在元组的该部分具有该值时匹配。考虑到这一点,我会将你的匹配表达式写成这样:

let rec createActivities(hl: (string * Nat * Nat) list): Activity list = 
    match hl with
      | [] -> []
      | (name, pages, 0N) :: xs -> Read { bookName = name; pages = pages } :: createActivities xs
      | (name, duration, fileSize) :: xs -> Watch { movieName = name; duration = duration; fileSize = fileSize } :: createActivities xs

其工作原理是,match将按从上到下的顺序处理案例,并使用第一个匹配的案例。所以如果元组作为0N它的第三个元素,将使用第二个匹配情况,否则将使用第三个匹配情况。所以匹配表达式可以保持非常简单和干净。


推荐阅读