我在 FSharp 中有一系列seqs。如果谓词返回true,我想加入seq到前一个。
样品:
let items = seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]]
如果seq以1开头,我想加入一个seq到previos,所以结果应该是这样的:
seq [seq[2;3;4;1;5;6;7;1;9];seq[2;3;5;7]
]
有没有很好的功能方法呢?
我刚刚开始将我的长时间计算过程从C#转换为F#,并且即使在几个小时的工作和初学者对FSharp的了解之后我所能达到的性能改进也给我留下了深刻的印象。
我从亚马逊购买了一本名为'Beginning F#'的书。这真的很棒,但我现在主要应该使用seqs,列表,地图,集合,这个主题并没有像我需要的那样详细解释。有人会非常友好地告诉我一个关于这个话题的好资源吗?
提前谢谢!答案 0 :(得分:3)
let joinBy f input =
let i = ref 0
input
|> Seq.groupBy (fun x ->
if not (f x) then incr i
!i)
|> Seq.map (snd >> Seq.concat)
joinBy (Seq.head >> ((=) 1)) items
答案 1 :(得分:2)
与上一个问题一样,没有库函数可以做到这一点。最直接的解决方案是使用IEnumerator
命令性地写这个。但是,您可以编写更常用的函数(也可以用于其他目的)。
module Seq =
/// Iterates over elements of the input sequence and groups adjacent elements.
/// A new group is started when the specified predicate holds about the element
/// of the sequence (and at the beginning of the iteration).
/// For example:
/// Seq.groupWhen isOdd [3;3;2;4;1;2] = seq [[3]; [3; 2; 4]; [1; 2]]
let groupWhen f (input:seq<_>) = seq {
use en = input.GetEnumerator()
let running = ref true
// Generate a group starting with the current element. Stops generating
// when it founds element such that 'f en.Current' is 'true'
let rec group() =
[ yield en.Current
if en.MoveNext() then
if not (f en.Current) then yield! group()
else running := false ]
if en.MoveNext() then
// While there are still elements, start a new group
while running.Value do
yield group() }
要解决原始问题,您可以检查序列的第一个元素是否是1以外的数字。您将得到一个组序列,其中一个组是序列序列 - 然后您可以只连接组:
items
|> Seq.groupWhen (fun s -> Seq.head s <> 1)
|> Seq.map Seq.concat
编辑:我还在此处将该功能发布为一个代码段(具有很好的F#格式):http://fssnip.net/6A
答案 2 :(得分:2)
正如其他解决方案中所见,此问题几乎与您的last question相反。因此,为了更好地衡量,我将answer的修改版本提供给此处:
let concatWithPreviousWhen f s = seq {
let buffer = ResizeArray()
let flush() = seq {
if buffer.Count > 0 then
yield Seq.readonly (buffer.ToArray())
buffer.Clear() }
for subseq in s do
if f subseq |> not then yield! flush()
buffer.AddRange(subseq)
yield! flush() }
你这样使用它:
seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]]
|> concatWithPreviousWhen (Seq.head>>(=)1)
答案 3 :(得分:1)
看起来像我的折叠,如下所示。试图在没有ref值的情况下尽可能地发挥作用。
let joinBy f (s:'a seq seq) =
let (a:'a seq), (b:'a seq seq) =
s |> Seq.fold (fun (a,r) se ->
if f se then (se |> Seq.append a,r)
else (se, seq {yield! r; yield a} ) )
(Seq.empty, Seq.empty)
seq {yield! b; yield a} |> Seq.filter (Seq.isEmpty >> not)
seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]]
|> joinBy (Seq.head >> ((=) 1))
|> printfn "%A"