6

seq<#seq<'a>> ->seq<seq<'a>>(Zip2 や Zip3 のように 2 または 3 ではなく) 任意の数の入力シーケンスのシーケンスを取得し、結果としてタプルではなくシーケンスのシーケンスを返す Zip メソッドのように機能するシグネチャを持つ関数を作成したいと考えています。

つまり、次の入力があるとします。

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

結果を返します: [[1;4;7]; [2;5;8]; [3;6;9]]

リストの代わりにシーケンスを除いて。

私は F# を初めて使用しますが、必要な機能を備えた関数を作成しましたが、改善できることはわかっています。末尾再帰ではなく、もっと簡単にできるようですが、まだ方法がわかりません。int list listまた、2 番目の関数を使用せずに、必要な方法で署名を取得する (たとえば、入力として受け入れる) 良い方法も見つかりませんでした。

列挙子を直接使用してこれを実装できることは知っていますが、機能的な方法で実装することに興味があります。

これが私のコードです:

let private Tail seq = Seq.skip 1 seq
let private HasLengthNoMoreThan n = Seq.skip n >> Seq.isEmpty

let rec ZipN_core = function
    | seqs when seqs |> Seq.isEmpty -> Seq.empty
    | seqs when seqs |> Seq.exists Seq.isEmpty -> Seq.empty
    | seqs ->
        let head = seqs |> Seq.map Seq.head
        let tail = seqs |> Seq.map Tail |> ZipN_core
        Seq.append (Seq.singleton head) tail

// Required to change the signature of the parameter from seq<seq<'a> to seq<#seq<'a>>
let ZipN seqs = seqs |> Seq.map (fun x -> x |> Seq.map (fun y -> y)) |> ZipN_core
4

5 に答える 5

8
let zipn items = items |> Matrix.Generic.ofSeq |> Matrix.Generic.transpose

または、本当に自分で書きたい場合は、次のようにします。

let zipn items = 
  let rec loop items =
    seq {
      match items with
      | [] -> ()
      | _ -> 
        match zipOne ([], []) items with
        | Some(xs, rest) -> 
          yield xs
          yield! loop rest
        | None -> ()
    }
  and zipOne (acc, rest) = function
    | [] -> Some(List.rev acc, List.rev rest)
    | []::_ -> None
    | (x::xs)::ys -> zipOne (x::acc, xs::rest) ys
  loop items
于 2012-08-02T14:42:01.247 に答える
4

これは f# で aを記述するための標準的な答えのように思われるため、怠惰を維持し、関数のように完全なソース シーケンスを一度にメモリにロードすることを強制しないzipn「純粋な」ソリューションを追加したいと考えました。これは、a) 高速であり、b) 数百 MB のデータを含むシーケンスで動作するため、非常に重要なシナリオがあります。seqMatrix.transpose

これはおそらく、私がしばらくの間書いた中で最も慣用的な f# コードではありませんが、仕事は完了します (そして、関数型言語で手続き型コードを書くためにそれらを使用できないのに、なぜ f# にシーケンス式があるのでしょうか? )。

 let seqdata = seq {
  yield Seq.ofList [ 1; 2; 3 ]
  yield Seq.ofList [ 4; 5; 6 ]
  yield Seq.ofList [ 7; 8; 9 ]
}

let zipnSeq (src:seq<seq<'a>>) = seq {
  let enumerators = src |> Seq.map (fun x -> x.GetEnumerator()) |> Seq.toArray
  if (enumerators.Length > 0) then
    try 
      while(enumerators |> Array.forall(fun x -> x.MoveNext())) do 
        yield enumerators |> Array.map( fun x -> x.Current)
    finally 
      enumerators |> Array.iter (fun x -> x.Dispose())
}

zipnSeq seqdata |> Seq.toArray


val it : int [] [] = [|[|1; 4; 7|]; [|2; 5; 8|]; [|3; 6; 9|]|]

ちなみに、従来の行列転置は、@ Danielの回答よりもはるかに簡潔です。ただし、listorLazyList両方が最終的に完全なシーケンスをメモリに持つ必要があります。

let rec transpose = 
  function 
  | (_ :: _) :: _ as M -> List.map List.head M :: transpose (List.map List.tail M)
  | _ -> []
于 2014-11-05T17:00:19.577 に答える
2

さまざまな長さのサブリストを持つことを処理するために、要素が不足しているかどうかを見つけるためにオプションタイプを使用しました。

let split = function
    | []    -> None,    []
    | h::t  -> Some(h), t

let rec zipN listOfLists =
    seq { let splitted = listOfLists |> List.map split

          let anyMore = splitted |> Seq.exists (fun (f, _) -> f.IsSome)

          if anyMore then
              yield splitted |> List.map fst
              let rest = splitted |> List.map snd
              yield! rest |> zipN }

これはマップします

let ll = [ [ 1; 2; 3 ];
           [ 4; 5; 6 ];
           [ 7; 8; 9 ] ]

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

let ll = [ [ 1; 2; 3 ];
           [ 4; 5; 6 ];
           [ 7; 8 ] ]

seq
    [seq [Some 1; Some 4; Some 7]; seq [Some 2; Some 5; Some 8];
     seq [Some 3; Some 6; null]]

これはあなたとは異なるアプローチを取りますが、以前に行った操作の一部(Seq.skip、Seq.appendなど)の使用を避けます。これには注意が必要です。

于 2012-08-02T11:32:47.157 に答える
0

別のオプション:

let zipN ls =
    let rec loop (a,b) =
        match b with
        |l when List.head l = [] -> a
        |l ->
            let x1,x2 =
                (([],[]),l)
                ||> List.fold (fun acc elem ->
                    match acc,elem with
                    |(ah,at),eh::et -> ah@[eh],at@[et]
                    |_ -> acc)
            loop (a@[x1],x2)
    loop ([],ls)
于 2019-06-15T21:48:54.183 に答える