Join 如何通过属性将seq附加到另一个seq?

Join 如何通过属性将seq附加到另一个seq?,join,f#,seq,Join,F#,Seq,我在FSharp中有一个序列。如果谓词返回true,我想将seq与前一个连接起来 样本: let items = seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]] 我想将seq与previos连接起来,如果seq从1开始,那么在这种情况下,结果应该是: seq[seq[2;3;4;1;5;6;7;1;9];seq[2;3;5;7]] 有什么好的实用方法吗 我刚刚开始将我漫长的计算过程从C#转换为F#,我对在短短几个小时的工作和我对FSharp的初级知

我在FSharp中有一个序列。如果谓词返回true,我想将seq与前一个连接起来

样本:

let items = seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]]
我想将seq与previos连接起来,如果seq从1开始,那么在这种情况下,结果应该是:

seq[seq[2;3;4;1;5;6;7;1;9];seq[2;3;5;7]
]

有什么好的实用方法吗

我刚刚开始将我漫长的计算过程从C#转换为F#,我对在短短几个小时的工作和我对FSharp的初级知识之后所能实现的性能改进印象深刻

我从亚马逊买了一本书,书名是《开始F》。这真的很好,但我现在主要应该处理seq、列表、地图和集合,而这个主题并没有像我需要的那样详细解释。有谁能为我提供一个关于这些主题的好资源


提前谢谢

与您的上一个问题一样,没有库函数可以完全做到这一点。最简单的解决方案是使用
IEnumerator
强制编写此代码。但是,您可以编写一个更通用的函数(也可以用于其他目的)

模块序列=
///迭代输入序列的元素并对相邻元素分组。
///当指定的谓词包含有关元素的内容时,将启动一个新组
///序列的(以及在迭代开始时)。
///例如:
///当isOdd[3;3;2;4;1;2]=序列[[3];[3;2;4];[1;2]]
当f(输入:seq)=seq时,设为groupWhen{
使用en=input.GetEnumerator()
让running=ref为真
//生成以当前元素开头的组。停止生成
//当它找到元素时,使得“f en.Current”为“true”
let rec group()=
[当前产量]
如果en.MoveNext()那么
如果不是(f en.Current),则产生!组()
正在运行的else:=false]
如果en.MoveNext()那么
//当仍有元素时,启动一个新组
在运行时。值是多少
屈服群()}
为了解决最初的问题,您可以检查序列的第一个元素是否是1以外的数字。您将得到一个组序列,其中一个组是一个序列序列-然后您可以将这些组连接起来:

items 
  |> Seq.groupWhen (fun s -> Seq.head s <> 1)
  |> Seq.map Seq.concat
项目
|>Seq.groupWhen(乐趣->Seq.heads 1)
|>顺序图顺序混凝土

编辑:我还将函数作为一个片段(具有良好的F#格式)发布在这里:

正如在其他解决方案中所看到的,这个问题几乎与您的问题相反。因此,为了更好地衡量,我在这里给出了我的修订版本:

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)

看起来像一个折叠,如下所示。尝试在没有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"

这似乎不起作用,它返回与输入相同的输出(使用OP的示例)@Stephen-你确定吗?我刚刚将代码从SO复制到Visual Studio,它工作得很好。。。OP输入的结果是
[[2;3;4;1;5;6;7;1;9];[2;3;5;7]]
(转换为列表时)。Ooops-显然我错了,它工作正常。在我发表评论之前,我进行了三次检查,所以我不知道为什么我之前得到了不好的结果(可能我有一些奇怪的FSI缓存或其他东西,因为我正在使用所有不同的解决方案,刚刚再次测试,我首先重置了会话)。@Stephen-没问题。很高兴听到它真的起作用了:-)。是的,很抱歉,我可以想象它可能会阻碍你的投票:(它与我对他上一个问题的回答有很好的对称性。+1表示很好且较短的解决方案:-)。虽然我喜欢它更短的事实,但它依赖于
Seq.groupBy
以某种方式实现的事实。这绝对不是问题(只要有测试)。但是,我试图避免声明性函数(如
Seq.groupBy
)的参数中的可变变量,以保持您可以用并行实现等替换
Seq.groupBy
的良好属性,并且它仍然可以工作。(也就是说,我认为使用不纯函数作为
Seq
组合子的参数是“作弊”,但作弊通常是好的)。@Tomas:这一点很好。这取决于
groupBy
是顺序的,但这是一个相当安全的假设,因为有一个单独的模块,
PSeq
,专门用于“非顺序”执行,对吗?@Tom:回应Tomas的观点:这取决于
groupBy
的顺序行为。如果这让你感到恶心,那你自己滚也没什么大不了的这是一种方法(顺便说一句,这与F#中的方法非常相似)。@Daniel-是的,我认为这是一种安全的假设,用于
Seq
(我不认为有人会想将其更改为非顺序)。我认为这主要是风格或哲学上的东西。
seq [seq[2;3;4];seq[1;5;6;7;1;9];seq[2;3;5;7]]
|> concatWithPreviousWhen (Seq.head>>(=)1)
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"