Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.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中的列表中提取单个元素#_F#_Functional Programming_Sequence - Fatal编程技术网

F# 从F中的列表中提取单个元素#

F# 从F中的列表中提取单个元素#,f#,functional-programming,sequence,F#,Functional Programming,Sequence,我想从F#中的序列中提取一个项目,如果没有或有多个项目,则给出一个错误。最好的方法是什么 我现在有 let element = data |> (Seq.filter (function | RawXml.Property (x) -> false | _ -> true)) |> List.of_seq |> (function head :: [] -> head | head :

我想从F#中的序列中提取一个项目,如果没有或有多个项目,则给出一个错误。最好的方法是什么

我现在有

let element = data |> (Seq.filter (function | RawXml.Property (x) -> false | _ -> true))
                   |> List.of_seq
                   |> (function head :: [] -> head | head :: tail -> failwith("Too many elements.") | [] -> failwith("Empty sequence"))
                   |> (fun x -> match x with MyElement (data) -> x | _ -> failwith("Bad element."))
这似乎有效,但这真的是最好的方法吗

编辑:当我被指向正确的方向时,我想到了以下几点:

let element = data |> (Seq.filter (function | RawXml.Property (x) -> false | _ -> true))
                   |> (fun s -> if Seq.length s <> 1 then failwith("The sequence must have exactly one item") else s)
                   |> Seq.hd
                   |> (fun x -> match x with MyElement (_) -> x | _ -> failwith("Bad element."))
let element=data |>(Seq.filter(函数| RawXml.Property(x)->false | |->true))
|>(fun s->if Seq.length s1然后failwith(“序列必须正好有一个项目”)或s)
|>Seq.hd
|>(乐趣x->将x与MyElement()->x |)->failwith(“坏元素”)匹配)

我想这会好一点。

序列有一个查找功能

val find : ('a -> bool) -> seq<'a> -> 'a

valfind:('a->bool)->seq以现有序列标准函数的样式完成

#light

let findOneAndOnlyOne f (ie : seq<'a>)  = 
    use e = ie.GetEnumerator()
    let mutable res = None 
    while (e.MoveNext()) do
        if f e.Current then
            match res with
            | None -> res <- Some e.Current
            | _ -> invalid_arg "there is more than one match"          
    done;
    match res with
        | None -> invalid_arg "no match"          
        | _ -> res.Value
#灯
让Findone和Donlyone f(即:seq使用:

> let only s =
    if not(Seq.isEmpty s) && Seq.isEmpty(Seq.skip 1 s) then
      Seq.hd s
    else
      raise(System.ArgumentException "only");;
val only : seq<'a> -> 'a
>就让我们=
如果不是(顺序为isEmpty s)和&顺序为isEmpty(顺序为skip 1 s),则
Seq.hds
其他的
raise(仅限System.ArgumentException);;

val only:seqMy two Second…这与选项类型一起工作,因此我可以在自定义monad中使用它。可以很容易地进行修改,但可以处理异常

let Single (items : seq<'a>) =
    let single (e : IEnumerator<'a>) =
        if e.MoveNext () then
            if e.MoveNext () then
                raise(InvalidOperationException "more than one, expecting one")
            else
                Some e.Current
        else
            None
    use e = items.GetEnumerator ()
    e |> single
let Single(项目:序号)=
如果e.MoveNext()那么
如果e.MoveNext()那么
引发(InvalidOperationException“多个,应为一个”)
其他的
一些e.电流
其他的
没有一个
使用e=items.GetEnumerator()
e |>单曲

使用现有库函数有什么问题

let single f xs = System.Linq.Enumerable.Single(xs, System.Func<_,_>(f))

[1;2;3] |> single ((=) 4)
single f xs=System.Linq.Enumerable.single(xs,System.Func(f))
[1;2;3]|>单个(=)4)

更新后的答案是使用Seq.exactlyOne,它会引发ArgumentException

你能提供一个样本序列和你在寻找什么吗?我觉得没有必要。我想找到第一个值,如果有多个值,就给出一个错误。这就是+1-你想要一个F#等价于一个有用的LINQ运算符(System.Linq.Enumerable.Single)-通常情况下,情况正好相反!在具有许多匹配项的长序列上,这将非常缓慢地失败,在无限序列上,正确的结果是继续计算到无穷大或提前终止,但两者都不会(尽管这一差异在效用上非常微小)是的,我认为无限seq会让你得到任何一种方式,试着找到一些不在无限列表中的东西…但是,测量长度而不是仅仅检查尾部是否为空是一个好的点,我最初想提到的是,但是seq没有尾部函数。我修改了我的帖子以反映这种限制和使用一个O(1)的函数。ThanksSeq的skip函数将作为tail的替代函数,Seq.skip 1过滤器应为空,之后Seq.hd将检查它至少有一个(如果为空,hd将抛出自己的异常,这很有用)不要同时计算头部(因此如果有副作用,您会看到两次)?是的。如果它们速度慢或有不良副作用,则您需要对此进行优化。在第二次调用
MoveNext
之前,您可能应该缓存
e.Current
,因为如果在到达枚举结束后访问
e.Current
,某些枚举器可能会引发异常。此外,我没有看到任何好处t创建嵌套的
single
函数,因为它总是被精确调用一次。如果有0个元素,则返回
None
,但如果元素多于1,则抛出异常,这似乎很奇怪-在这种情况下,我将调用方法
AtMostOne
,而不是
single
。嵌套函数就是为了c而存在的lear它实际上是在IEnumerator上工作的,而不是IEnumerable。none和一些是存在的,因此这插入到我的maybe monad中,在这种情况下它读起来非常自然。我在数据访问中经常使用它来链接依赖调用。当没有短路时,当一些继续时,使用选项类型是可以的,但是为什么不返回
N一个
如果还有多个元素?对我来说,如果你希望有一个元素,那么0元素和2元素或更多元素的情况可能同样例外,应该以同样的方式处理,除非有令人信服的理由来区分它们(在这种情况下,为了清晰起见,该方法可能应该被称为更具体的方法,如
AtMostOne
)。这是System.Linq中唯一一个在F#模块中没有等价物的扩展方法。不确定是否有这样的原因。