F # эквивалент LINQ Single - PullRequest
2 голосов
/ 24 марта 2012

Хорошо, поэтому для большинства операций LINQ есть эквивалент F #.(Как правило, в модуле Seq, поскольку Seq = IEnumerable)

Я не могу найти эквивалент IEmumerable.Single, я предпочитаю Single вместо First (то есть Seq.find), потому что этоболее оборонительный - он утверждает, что я ожидаю состояние.

Так что я вижу пару решений (кроме использования Seq.find).(Они могут быть написаны как методы расширения)

Сигнатура типа для этой функции, которую я вызываю только, является

('a->bool) -> seq<'a> -> 'a

let only =  fun predicate src -> System.Linq.Enumerable.Single<'a>(src, predicate)

let only2 = Seq.filter >> Seq.exactlyOne

only2, но не будеткомпилировать (есть какие-нибудь подсказки?).

Ответы [ 2 ]

2 голосов
/ 24 марта 2012

В F # 2.0 это решение работает без перечисления всей последовательности (близко к вашему второму подходу):

module Seq =
    let exactlyOne seq =
        match seq |> Seq.truncate 2 with
        | s when Seq.length s = 1 -> s |> Seq.head |> Some
        | _ -> None

    let single predicate =
        Seq.filter predicate >> exactlyOne

Я предпочитаю возвращать тип option, так как возбуждающее исключение довольно необычно в функциях высокого порядка F #.

EDIT:

В F # 3.0, как отметил @Oxinabox в своем комментарии, Seq.exactlyOne существует в модуле Seq.

2 голосов
/ 24 марта 2012

А как же

let Single source f =
    let worked = ref false
    let newf = fun a -> 
        match f a with
        |true -> 
            if !worked = true then failwith "not single"
            worked := true
            Some(a)
        |false -> None
    let r = source |> Seq.choose newf
    Seq.nth 0 r 

Очень неидиоматично, но, вероятно, близко к оптимальному

EDIT:

Решение с exactlyOne

let only2 f s= (Seq.filter f s) |> exactlyOne
...