Объединить 2 последовательности - PullRequest
1 голос
/ 05 мая 2019

Я пытаюсь воссоздать свою собственную функцию Seq.zip.Он должен делать то же самое, что и Seq.zip, но только с использованием seq для его создания.Вот мой код:

let rec seqZip s1 s2 =
    seq {
        let e1 = Seq.item 0 s1
        let e2 = Seq.item 0 s2

        let rec helper s1 s2 n =
            match s1, s2 with
            | s1, s2 when n > s1.Length && n > s2.Length -> yield ()
            | s1, s2 -> yield (Seq.item (n+1) s1, Seq.item (n+1) s2)

        helper s1 s2 0
    } 

Я не уверен, что мне даже нужна вспомогательная функция, но есть ли у вас какие-либо предложения?

Ответы [ 2 ]

6 голосов
/ 05 мая 2019

Объявление типа seq<'a> является псевдонимом типа для System.Collections.Generic.IEnumerable<'a>. Этот интерфейс предоставляет перечислитель, с помощью которого мы можем перебирать коллекцию, все функции более высокого уровня также будут зависеть от этих интерфейсов. Поэтому итерация последовательности с помощью метода MoveNext() и свойства Current должна быть наиболее эффективным способом.

let zip (s1 : seq<_>) (s2 : seq<_>) =
    use e1 = s1.GetEnumerator()
    use e2 = s2.GetEnumerator()
    let rec loop () = seq{
        if e1.MoveNext() && e2.MoveNext() then
            yield e1.Current, e2.Current
            yield! loop() }
    loop()

zip [1..3] [11..14] |> Seq.toList
// val it : (int * int) list = [(1, 11); (2, 12); (3, 13)]
Seq.zip [1..3] [11..14] |> Seq.toList
// val it : (int * int) list = [(1, 11); (2, 12); (3, 13)]

Вложенная вспомогательная функция прекрасно инкапсулирует рекурсию.

0 голосов
/ 09 мая 2019

Более ориентированное на последовательность решение:

let rec seqzip (a: 'a seq) (b: 'b seq): ('a*'b) seq =
    match a with
    | empty when Seq.isEmpty empty -> Seq.empty<'a*'b>
    | aa ->
        match b with
        | empty when Seq.isEmpty empty -> Seq.empty<'a*'b>
        | bb -> seq{
            yield (Seq.head aa, Seq.head bb)
            yield! (seqzip (Seq.tail aa) (Seq.tail bb))
            }
...