List 如何在f#中编辑可变列表中的项目,并允许列表中的其他项目保留其值?

List 如何在f#中编辑可变列表中的项目,并允许列表中的其他项目保留其值?,list,f#,mutable,List,F#,Mutable,我在f#named tickets中创建了一个列表,其中包含10条名为Ticket的记录。这些记录都用它们的特定座位号和空客户名称初始化 type Ticket = {seat:int; customer:string} let mutable tickets = [for n in 1..10 -> {Ticket.seat = n; Ticket.customer = ""}] 我想编写一个函数,在列表中预订一个特定的座位(在座位上添加客户姓名)。 如何编辑列表中的某个项目,而使

我在f#named tickets中创建了一个列表,其中包含10条名为Ticket的记录。这些记录都用它们的特定座位号和空客户名称初始化

type Ticket = {seat:int; customer:string}  
let mutable tickets = [for n in 1..10 -> {Ticket.seat = n; Ticket.customer = ""}]
我想编写一个函数,在列表中预订一个特定的座位(在座位上添加客户姓名)。 如何编辑列表中的某个项目,而使其他项目仍保留其值

功能性F#列表类型是不可变的,这意味着您无法更改它。使用它的典型方式是返回一个新的、修改过的副本

为此,您可以编写一个函数
bookSeat
,该函数将
list
与number&new name结合起来,生成一个新的
list
,其中一个字段已更新:

let bookSeat seatNo name tickets = 
  tickets |> List.map (fun ticket ->
    if ticket.seat = seatNo then { ticket with customer = name }
    else ticket )

bookSeat 3 "Tomas" tickets

下面是一种使用可变(参考单元格)票证列表的方法:

显然,如果您想
添加
座位,而不是用所有明显的座位初始化它们,那么您也可以使
票证
本身可变

更好的方法(?) 但我认为这是错误的做法——我认为你想要一张地图:

type Ticket = {seat:int; customer:string}  
type Tickets = Map<int, Ticket>

let bookSeat seat name (tickets : Tickets) =
    match Map.tryFind seat tickets with
    | Some oldTicket ->
        tickets 
        |> Map.remove seat
        |> Map.add seat { oldTicket with customer = name }
    | None ->
        tickets
        |> Map.add seat { seat = seat; customer = name }
在这里,您不必到处传递
票证
——它们将在适当的位置发生变异(但是
票证
——对象本身仍然是不可变的)


请注意,现在这不是线程安全的,所以要小心。

我认为这里最惯用的方法是简单地使用
字符串数组。如果您事先知道大小,并且希望能够对其进行更新,那么这就是最惯用的满足这两种需求的结构。所以

// create 10-element string array initialized with null
let (tickets : string array) = Array.zeroCreate 10 

...

tickets.[3] <- "New Customer"
//创建用null初始化的10元素字符串数组
let(票证:字符串数组)=array.zeroCreate 10
...

票。[3]你在哪一部分卡住了?@JohnPalmer我在某处读到,在f#中,如果我想更改列表中的项目,我必须创建一个新列表。这就是我想到的。但新列表现在只有一项。let bookTicket()=Console.WriteLine(“输入座位号:”)let seatNo=int(Console.ReadLine())Console.WriteLine(“输入客户名称:”)let customerName=string(Console.ReadLine())tickets@CharlesUko,这是真的,在这种情况下(如果您真的想改变情况)我只想使用
System.Collection.Generic.list这几乎是这个问题的重复:@JohnPalmer很好的观点-我认为(功能)列表无论如何都是错误的数据表示形式
type Ticket = {seat:int; customer:string}  
let tickets = System.Collections.Generic.Dictionary<int, Ticket>()

let bookSeat seat name =
    match tickets.TryGetValue seat with
    | (true, oldTicket) ->
        tickets.[seat] <- { oldTicket with customer = name }
    | (false, _) ->
        tickets.[seat] <- { seat = seat; customer = name }
// create 10-element string array initialized with null
let (tickets : string array) = Array.zeroCreate 10 

...

tickets.[3] <- "New Customer"