seq使うのむずかし。(Seq.skipおそい)
まとめ
- seq式で遊ぼうとした
- combinationsとか生成すれば良さそう。
- 全部seqにすると遅い。
seq式で遊ぼうとした
seq式は値の列を返す計算を返してくれる。
> seq {for x in [1..10] do yield x*x} |> Seq.toList;; val it : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
- 要素を結果として与えてくれるyield
- 列をconcatしてくれるyield!
の2つがある。
> seq {yield 1; yield 2; yield 3};; val it : seq<int> = seq [1; 2; 3] > seq {yield! [1;2;3]; yield 4; yield! [5]};; val it : seq<int> = seq [1; 2; 3; 4; ...]
全部seqにすると遅い。
[1..20]までの列から8個取る組み合わせを列挙してみる
$ time ./permtations.exe ...]./permtations.exe 39.82s user 0.81s system 176% cpu 23.075 total
すっごい遅い。
profilerを使ってみる。
monoなので以下のような感じでprofiler使う。
$ mono --profile=default:stat permtations.exe prof counts: total/unmanaged: 2383/1115 1014 42.57 % mono() 349 14.65 % Microsoft.FSharp.Collections.SeqModule/Skip@1428<int>:GenerateNext (System.Collections.Generic.IEnumerable`1<int>&) 267 11.21 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:MoveNextImpl () 109 4.58 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:System-Collections-IEnumerator-MoveNext () 69 2.90 % (wrapper alloc) object:Alloc (intptr) 60 2.52 % Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1<int>:System-Collections-Generic-IEnumerator`1-get_Current () 53 2.23 % Microsoft.FSharp.Core.Operators/OperatorIntrinsics/BaseRangeEnumerator`1<int>:System-Collections-IEnumerator-MoveNext () 43 1.81 % Microsoft.FSharp.Collections.PrivateListHelpers/ListEnumerator`1<int>:System-Collections-IEnumerator-MoveNext () 34 1.43 % (wrapper managed-to-native) object:__icall_wrapper_mono_object_new_fast (intptr) 34 1.43 % Microsoft.FSharp.Collections.SeqModule/Skip@1428<int>:Close ()
Seq.skipが遅い。Seq.skipが遅い。
Seq.skip
Seq.skipはdropみたいなもの。N個飛ばした列を返す
> seq {yield 1; yield 2} |> Seq.skip 1;; val it : seq<int> = seq [2] > [1;2;3] |> List.tail;; val it : int list = [2; 3]
Seq.skip使っている箇所をlistに置き換えてみる。
$ time ./permtations2.exe ...]./permtations2.exe 2.63s user 0.11s system 173% cpu 1.575 total
早くなった。
ちなみに
pythonのitertolsを使った場合はこれくらいの速度([:20]はf#の出力に大体合わせるため)
$ time python -c "import itertools as i; print [x for x in i.combinations(range(20),8)][:20]" [~/sandbox/fsharp] [(0, 1, 2, 3, 4, 5, 6, 7), (0, 1, 2, 3, 4, 5, 6, 8), (0, 1, 2, 3, 4, 5, 6, 9), (0, 1, 2, 3, 4, 5, 6, 10), (0, 1, 2, 3, 4, 5, 6, 11), (0, 1, 2, 3, 4, 5, 6, 12), (0, 1, 2, 3, 4, 5, 6, 13), (0, 1, 2, 3, 4, 5, 6, 14), (0, 1, 2, 3, 4, 5, 6, 15), (0, 1, 2, 3, 4, 5, 6, 16), (0, 1, 2, 3, 4, 5, 6, 17), (0, 1, 2, 3, 4, 5, 6, 18), (0, 1, 2, 3, 4, 5, 6, 19), (0, 1, 2, 3, 4, 5, 7, 8), (0, 1, 2, 3, 4, 5, 7, 9), (0, 1, 2, 3, 4, 5, 7, 10), (0, 1, 2, 3, 4, 5, 7, 11), (0, 1, 2, 3, 4, 5, 7, 12), (0, 1, 2, 3, 4, 5, 7, 13), (0, 1, 2, 3, 4, 5, 7, 14)] python -c 0.07s user 0.01s system 93% cpu 0.086 total