我对函数式编程相当新,并且在列表处理任务方面存在一些问题.我有一系列记录,如下所示: type TestRec = { Id : string Amount : int } 现在我想删除列表中彼此构建一对的所有项目.例如,如果有
type TestRec = { Id : string Amount : int }
现在我想删除列表中彼此构建一对的所有项目.例如,如果有两个项目的金额为7和-7,则应从列表中删除这两个项目.如果存在Amount = 7的第三个元素,则它应该保留在列表中.
我希望你们能理解我想要做的事情.这是我到目前为止提出的(但它还没有正常工作):
let removeDoubles items = items |> Seq.groupBy (fun i -> Math.Abs(i.Amount)) |> Seq.map snd |> Seq.filter (fun i -> Seq.length i = 1)
编辑:
确定两个元素是否彼此匹配的函数可能比上面描述的更复杂(Math.Abs).我认为这将是Amount值的一个很好的例子,但它可以是任何谓词函数.
编辑2:
为了澄清更多,我想对可能的相关问题给出更真实的描述.您可以想象一下发票的计算,其中列表包含所有发票头寸.现在,您要删除所有具有相同“商品编号”,“货币”且价格评估为零的发票头寸对.
也许这个例子有助于解释我的问题.我只是认为解决这个问题可能有一个更“功能性的方法”,就是让两个循环在列表上运行并删除像我在命令式语言中那样的元素.
为了抽象出对立的想法,我定义了两个函数.一个用于关系相等(相关),另一个用于定义取消(相反).该功能首先将相关对象分组在一起,然后将它们分成相对的数组.然后根据所需的取消数量对这些得到的阵列进行切片.最后,所有内容都汇总在一起.
type TestRec = { Id : string; Amount : int; } let removeDoubles items related opposite = items |> Seq.groupBy related |> Seq.map (fun (key, values) -> let t, f = values |> Seq.toArray |> Array.partition opposite if t.Length > f.Length then t.[.. t.Length - f.Length - 1] else f.[.. f.Length - t.Length - 1] ) |> Seq.concat let items = [ {Id="first";Amount=7}; {Id="seconds";Amount=7}; {Id="we";Amount=4}; {Id="negative";Amount= -7} ] let test = removeDoubles items (fun x -> abs x.Amount) (fun x -> x.Amount > 0) printf "%A" test System.Console.ReadLine() |> ignore
输出
seq [{Id = "first"; Amount = 7;}; {Id = "we"; Amount = 4;}]