Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#折叠三元组中的序列_F#_Fold - Fatal编程技术网

F#折叠三元组中的序列

F#折叠三元组中的序列,f#,fold,F#,Fold,我在谷歌上搜索和阅读过,我试图找到一种“正确”的方式来做,但我读到的每一个问题似乎都有完全不同的答案 这是我问题的要点。文件的类型签名为三元组中的一个序列(a:string,b:string,c:Int64)。作为f#的新手,我仍然不能流利地表达类型签名(或者理解它们)。a是文件名,b是内部标识符,c是表示文件长度(大小)的值。baseconfig是代码前面的一个字符串 ignore(files |> Seq.filter( fun(x,y,z) -> y = basec

我在谷歌上搜索和阅读过,我试图找到一种“正确”的方式来做,但我读到的每一个问题似乎都有完全不同的答案

这是我问题的要点。文件的类型签名为三元组中的一个序列(a:string,b:string,c:Int64)。作为f#的新手,我仍然不能流利地表达类型签名(或者理解它们)。a是文件名,b是内部标识符,c是表示文件长度(大小)的值。baseconfig是代码前面的一个字符串

ignore(files 
    |> Seq.filter( fun(x,y,z) ->  y = baseconfig)  // used to filter only files we want
    |> Seq.fold( fun f n   -> 
        if( (fun (_,_,z) -> z) n > 50L*1024L*1024L) then
            zipfilex.Add((fun (z:string, _, _) -> z) n)
            printfn("Adding 50mb to zip")
            zipfilex.CommitUpdate()
            zipfilex.BeginUpdate()
            ("","",0L)
        else
            zipfilex.Add((fun (z, _, _) -> z) n)
            ("", "", (fun (_, _, z:Int64) -> z) n + (fun (_, _, z:Int64) -> z) f)
    ) ("","",0L)
    )
这段代码应该做的是迭代
文件中的每个文件,将其添加到zip存档(但不是真的,它只是在稍后提交的列表中),当文件超过50MB时,将当前挂起的文件提交到zip存档。添加文件成本很低,提交成本很高,因此我尝试通过批处理来降低成本

到目前为止,代码还可以工作。。。除了ObjectDisposedException,当它接近150MB的提交文件时,我得到了它。但我不确定这样做是否正确。感觉上我在以一种非传统的方式使用
Seq.fold
,但是,我不知道有什么更好的方法

附加问题:有没有更好的方法从元组中删除值?fst和snd只适用于2值元组,我意识到您可以定义自己的函数,而不是像我那样内联它们,但似乎应该有更好的方法

更新:我以前在fold的尝试中,我不明白为什么我不能仅仅使用Int64作为累加器。结果我遗漏了一些关键的括号。下面是一个简单的版本。还消除了所有疯狂的元组提取

ignore(foundoldfiles 
    |> Seq.filter( fun (x,y,z) ->  y = baseconfig) 
    |> Seq.fold( fun (a) (f,g,j)   -> 
        zipfilex.Add( f)
        if( a > 50L*1024L*1024L) then
            printfn("Adding 50mb to zip")
            zipfilex.CommitUpdate()
            zipfilex.BeginUpdate()
            0L
        else
             a + j
    ) 0L
    )
更新2:我将不得不采用一种强制性的解决方案,在zip文件在随后的语句中关闭后,F#以某种方式重新输入这段代码。这解释了ObjectDisposedException。不知道这是怎么回事,也不知道为什么。

以下是我的看法:

let inline zip a b = a, b

foundoldfiles 
|> Seq.filter (fun (_, internalid, _) -> internalid = baseconfig)
|> zip 0L
||> Seq.fold (fun acc (filename, _, filesize) -> 
    zipfilex.Add filename
    let acc = acc + filesize
    if acc > 50L*1024L*1024L then
        printfn "Adding 50mb to zip"
        zipfilex.CommitUpdate ()
        zipfilex.BeginUpdate ()
        0L
    else acc)
|> ignore
一些注意事项:

  • zip
    helper函数可以在整个函数中创建一个干净的管道,而不会产生任何开销,在更复杂的场景中,由于状态从
    fold
    functor的右侧移到左侧,因此有助于类型推断(尽管在这种特殊情况下,这并不重要,也没有帮助)
  • 使用
    \uu
    在本地丢弃不需要的元组元素可以使代码更易于阅读
  • 通过管道传输到
    ignore
    而不是用额外的括号包装整个表达式的方法使代码更易于阅读
  • 将一元函数的参数用括号括起来看起来很奇怪;不能对非一元货币函数使用括号,因此对一元函数使用括号是不一致的。我的策略是为构造函数调用和元组函数调用保留括号
编辑:注意
如果(a>50L*1024L*1024L)那么
是不正确的逻辑-
如果
需要考虑累加器和当前文件大小。例如,如果第一个文件>=50MB,则不会触发if。

以下是我的看法:

let inline zip a b = a, b

foundoldfiles 
|> Seq.filter (fun (_, internalid, _) -> internalid = baseconfig)
|> zip 0L
||> Seq.fold (fun acc (filename, _, filesize) -> 
    zipfilex.Add filename
    let acc = acc + filesize
    if acc > 50L*1024L*1024L then
        printfn "Adding 50mb to zip"
        zipfilex.CommitUpdate ()
        zipfilex.BeginUpdate ()
        0L
    else acc)
|> ignore
一些注意事项:

  • zip
    helper函数可以在整个函数中创建一个干净的管道,而不会产生任何开销,在更复杂的场景中,由于状态从
    fold
    functor的右侧移到左侧,因此有助于类型推断(尽管在这种特殊情况下,这并不重要,也没有帮助)
  • 使用
    \uu
    在本地丢弃不需要的元组元素可以使代码更易于阅读
  • 通过管道传输到
    ignore
    而不是用额外的括号包装整个表达式的方法使代码更易于阅读
  • 将一元函数的参数用括号括起来看起来很奇怪;不能对非一元货币函数使用括号,因此对一元函数使用括号是不一致的。我的策略是为构造函数调用和元组函数调用保留括号

编辑:注意
如果(a>50L*1024L*1024L)那么
是不正确的逻辑-
如果
需要考虑累加器和当前文件大小。例如,如果第一个文件>=50MB,则不会触发if。

我认为您的问题不会因为使用
折叠而受益。它在构建不可变结构时最有用。在这种情况下,我的观点是,它让你试图做的事情变得不那么清晰。强制解决方案运行良好:

let mutable a = 0L
for (f, g, j) in foundoldfiles do
    if g = baseconfig then
        zipfilex.Add(f)
        if a > 50L * 1024L * 1024L then
            printfn "Adding 50mb to zip"
            zipfilex.CommitUpdate()
            zipfilex.BeginUpdate()
            a <- 0L
        else
            a <- a + j
让可变a=0L
对于foundoldfiles中的(f,g,j)do
如果g=baseconfig,则
zipfilex.Add(f)
如果a>50L*1024L*1024L,则
打印fn“将50mb添加到zip”
zipfilex.CommitUpdate()
zipfilex.BeginUpdate()

a我不认为你的问题从使用
fold
中获益。它在构建不可变结构时最有用。在这种情况下,我的观点是,它让你试图做的事情变得不那么清晰。强制解决方案运行良好:

let mutable a = 0L
for (f, g, j) in foundoldfiles do
    if g = baseconfig then
        zipfilex.Add(f)
        if a > 50L * 1024L * 1024L then
            printfn "Adding 50mb to zip"
            zipfilex.CommitUpdate()
            zipfilex.BeginUpdate()
            a <- 0L
        else
            a <- a + j
让可变a=0L
对于foundoldfiles中的(f,g,j)do
如果g=baseconfig,则
zipfilex.Add(f)
如果a>50L*1024L*1024L,则
打印fn“将50mb添加到zip”
zipfilex.CommitUpdate()
zipfilex.BeginUpdate()

a作为“脏”命令式样式的替代,您可以使用一个通用且可重用的分块函数扩展
Seq
模块。该函数有点像
fold
,但它使用返回
选项的lambda作为“dirty”命令式样式的替代,您可以使用用于分块的通用和可重用函数扩展
Seq
模块。这个函数有点像
fold
,但是如果你不喜欢mutab,它需要一个lambda返回
选项
let rec loop acc = function
    | (file, id, size) :: files ->
        if id = baseconfig then
            zipfilex.Add file
            if acc > 50L*1024L*1024L then
                printfn "Adding 50mb to zip"
                zipfilex.CommitUpdate()
                zipfilex.BeginUpdate()
                loop 0L files
            else
                loop (acc + size) files
        else
            loop acc files
    | [] -> ()

loop 0L foundoldfiles
let rec loop acc = function
    | (file, id, size) :: files when id = baseconfig ->
        zipfilex.Add file
        if acc > 50L*1024L*1024L then
            printfn "Adding 50mb to zip"
            zipfilex.CommitUpdate()
            zipfilex.BeginUpdate()
            loop 0L files
        else
            loop (acc + size) files
    | _ :: files -> loop acc files
    | [] -> ()

loop 0L foundoldfiles