F#折叠三元组中的序列
|
我已经在Google上搜索并阅读了,我正试图找到一种“正确的”方式来做,但是我在SO上阅读的每个问题似乎都有完全不同的答案。
这是我的问题的要点。文件具有三重序列的类型签名(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)
)
该代码段应该执行的操作是遍历files
中的每个文件,将其添加到zip归档文件中(但实际上不是,它只是在列表中稍后提交),然后当文件超过50MB时,提交当前待处理的文件到zip存档。添加文件很便宜,提交也很昂贵,因此我尝试通过批量处理来降低成本。
到目前为止,代码还可以工作...除了ObjectDisposedException接近150MB的提交文件时,我得到了。但是我不确定这是执行此操作的正确方法。感觉我在以非常规方式使用Seq.fold
,但是我不知道有更好的方法。
额外的问题:是否有更好的方法从元组中剔除值? fst和snd仅适用于2个值元组,并且我意识到您可以定义自己的函数,而不必像我那样内联它们,但是似乎应该有更好的方法。
更新:我以前尝试折叠时,我不明白为什么我不能只使用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。不知道它是如何工作的或为什么。
没有找到相关结果
已邀请:
4 个回复
芜任亮蜡
渴翅吮斡撤
模块,以进行分块。该函数有点像
,但是它需要一个返回
的lambda。如果返回“ 9”,则开始一个新的块,否则将元素添加到前一个块。然后,您可以编写一个优雅的解决方案:
函数的实现要长一点-它需要直接使用
,并且可以使用递归表示:
锹缄
一些注意事项:
helper函数使整个函数的流水线整洁而没有任何开销,并且在更复杂的情况下,由于状态从
函子的右侧转移到左侧,有助于类型推断(尽管不是这样)重要事项或帮助) 使用ѭ17局部丢弃不需要的元组元素使代码更易于阅读 流水线到ѭ18中的方法,而不是用多余的括号包装整个表达式,使代码更易于阅读 用括号括起一元函数的参数看起来很奇怪。您不能将括号用于非一元咖喱函数,因此将其用于一元函数是不一致的。我的政策是为构造函数调用和元组函数调用保留括号 编辑:PS
是不正确的逻辑-
需要考虑累加器和当前文件大小。例如,如果第一个文件> = 50MB,则if不会触发。
坝胺绣敝
这样做的好处是,它明确说明了归纳案例可以继续进行的三种不同方式,以及每种情况下累加器的转换方式(因此,您不太可能出错)-见证Daniel's for循环中的错误版)。 您甚至可以将baseconfig检查移到when子句中: