List関数の確認

前にポーカー書いてた時に一個一個試してたList関数の確認履歴。
公式Docに乗ってる範囲しかサポートできてないけど。
https://msdn.microsoft.com/visualfsharpdocs/conceptual/collections.list-module-%5bfsharp%5d

```fsharp:listMethodFestival.fs
type Card = 
  {
    Number : int
    Suit : string
    Write : string
  }

let makeSuitCards suit = 
  [ for i in 1..13 -> 
    {
        Number = i;
        Suit = suit;
        Write = 
          match i with 
            | 1  -> "A"
            | 11 -> "J"
            | 12 -> "Q"
            | 13 -> "K"
            | _ -> i.ToString()
    }]

let makeDeck = makeSuitCards "H" @ makeSuitCards "C" @ makeSuitCards "S" @ makeSuitCards "D"
let cards = makeDeck
let cardsA = makeSuitCards "H"
let cardsB = makeSuitCards "C"
let cardsC = makeSuitCards "S"

// 合体
makeSuitCards "H"
|> List.append (makeSuitCards "C")
|> List.append (makeSuitCards "S")
|> List.append (makeSuitCards "D")
|> printfn "%A"

// 平均を求める　floatじゃないとあかんっぽい
[6;5;6;3;5;9] |> List.map(fun elm -> float elm) |> List.average |> printfn "%A"

// 平均を求める 使用項目を指定できる
cards |> List.averageBy(fun elm -> float elm.Number) |> printfn "%A"

// 指定条件に一致するものを抽出
cards |> List.choose(fun elm -> if elm.Number > 10 then Some(elm) else None) |> printfn "%A"

// 指定個数で分割
cards |> List.chunkBySize 4 |> printfn "%A"

// 関数適用してできたListをくっつけて返す(元のやつは含まれない)
cards |> List.collect(fun elm -> [for x in ["H";"C";"S"] -> {Number = elm.Number; Suit = x; Write = elm.Write}]) |> printfn "%A"

// リスト間の比較、違いがあるところまで調べて計算結果を返却、後続は見ない
[1;3;8] |> List.compareWith(fun elm1 elm2 -> elm1 - elm2) [1;3;1]  |> printfn "%A"
// -7

// リストの結合(感覚としてはjoinが近い)
List.concat [makeSuitCards "H"; makeSuitCards "C"; makeSuitCards "S"; makeSuitCards "D"] |> printfn "%A"

// 要素があるかどうか調べる
cards |> List.contains {Number = 1; Suit = "D"; Write = "A"} |> printfn "%A"

// キーを指定して要素数を調べる
cards |> List.countBy(fun elm -> elm.Number) |> printfn "%A"

// 完全に一致するものを省く
cards |> List.distinct |> printfn "%A"
cards |> List.map(fun elm -> elm.Number) |> List.distinct |> printfn "%A"

// 空のリストを作る 初期化用？
List.empty |> printfn "%A"

// 要素のプロパティを指定してあるかどうか調べる
cards |> List.exists(fun elm -> elm.Suit = "S") |> printfn "%A"

// リスト同士で存在チェック、ただし同じ要素数でなければならない
(makeSuitCards "H") |> List.exists2(fun elm1 elm2 -> elm1 = elm2) (makeSuitCards "H") |> printfn "%A"

// Chooseとの使い分けは正直よくわからない
cards |> List.filter(fun elm -> elm.Number > 10) |> printfn "%A"

// containsとは違って要素が返ってくる、なかったらKeyNotFoundException
cards |> List.find(fun elm -> elm = {Number = 1; Suit = "D"; Write = "A"}) |> printfn "%A"

// リストのインデックスが返ってくる(IndexOf)
cards |> List.findIndex(fun elm -> elm = {Number = 1; Suit = "D"; Write = "A"}) |> printfn "%A"

// 前の計算結果を引数としてもらってくる stateは初期値 accは多分stateから型が決められる
cards |> List.fold(fun acc elm -> acc + elm.Number) 0 |> printfn "%A"

// 前の計算結果を引数としてもらってくる 引数2個版
cardsA |> List.fold2(fun acc elm1 elm2 -> acc + elm1.Number + elm2.Number) 0 cardsB |> printfn "%A"

// 前の計算結果を引数としてもらってくる 逆版　|> で流し込めないので微妙に使いにくい？
List.foldBack(fun elm acc -> acc + elm.Number) cards 0 |> printfn "%A"

// 前の計算結果を引数としてもらってくる　後ろから 引数2個版
List.foldBack2(fun elm1 elm2 acc -> acc + elm1.Number + elm2.Number) cardsA cardsB 0 |> printfn "%A"

//中身が全部条件に一致するか調べる
cards |> List.forall(fun elm -> elm.Suit = "S") |> printfn "%b"
cardsA |> List.forall(fun elm -> elm.Suit = "H") |> printfn "%b"

//中身が全部条件に一致するか調べる リスト2個版
List.forall2(fun elm1 elm2 -> elm1.Suit = "H" && elm2.Suit = "C") cardsA cardsB |> printfn "%b"

// 先頭を取り出す lispのcar
cards |> List.head |> printfn "%A"

// リストを初期化
List.init 5 (
     fun elm -> {Number = elm + 1;
         Suit = "S";
         Write = 
           match elm + 1 with 
             | 1  -> "A"
             | 11 -> "J"
             | 12 -> "Q"
             | 13 -> "K"
             | _ -> (elm + 1).ToString()
     }
 ) |> printfn "%A"

// 空か調べる
cards |> List.isEmpty |> printfn "%b"
[] |> List.isEmpty |> printfn "%b"

// foreach
cardsA |> List.iter(fun elm -> printfn "%d" elm.Number)

// foreach 引数2個版
List.iter2(fun elm1 elm2 -> printfn "%d" (elm1.Number + elm2.Number)) cardsA cardsB

// foreach-index
cardsA |> List.iteri(fun i elm -> printfn "%d:%d" i elm.Number)

// foreach-index 引数2個版
List.iteri2(fun i elm1 elm2 -> printfn "%d:%d" i (elm1.Number + elm2.Number)) cardsA cardsB

// 長さ
cards |> List.length |> printfn "%d"

// 関数適用後の新しいリストを作る
cardsA |> List.map(fun elm -> elm.Number * 2) |> printfn "%A"

// 関数適用後の新しいリストを作る 引数2個
List.map2(fun elm1 elm2 -> elm1.Number * elm2.Number) cardsA cardsB |> printfn "%A"

// 関数適用後の新しいリストを作る 引数3個
List.map3(fun elm1 elm2 elm3 -> elm1.Number * elm2.Number * elm3.Number) cardsA cardsB cardsC |> printfn "%A"

// 関数適用後の新しいリストを作る index付き
cardsA |> List.mapi(fun i elm -> i * elm.Number * 2) |> printfn "%A"

// 関数適用後の新しいリストを作る 引数2個　index付き
List.mapi2(fun i elm1 elm2 -> i * elm1.Number * elm2.Number) cardsA cardsB |> printfn "%A"

// 関数適用後の新しいリストを作る 引数3個　index付きの関数はF#-Listの実装見てもないね、map3はあるのになんでやろう

// 最大値を取る
cards |> List.max |> printfn "%A"

// 最大値を取る、条件付き
cards |> List.maxBy(fun elm -> elm.Number = (List.max cards).Number && elm.Suit = "D" ) |> printfn "%A"

// 最小値を取る
cards |> List.min |> printfn "%A"

// 最小値を取る、条件付き -> なんかバグがある気がする。Number=13のものが返ってくる。
// 4.1が原因か？と思って最新コードで試してみたけど結果変わらず。issue投げるべきかもしれぬ。
cards |> List.minBy(fun elm -> elm.Number = (List.min cards).Number && elm.Suit = "C" ) |> printfn "%A"

// インデックス指定でアクセス(.[n]の実装？) -> duplicateになったらしい。ドキュメントには何も書いてないけど
List.nth cards 3 |> printfn "%A"

// nthのかわりにitemを使うとのこと
List.item 3 cards |> printfn "%A"

// 配列からリストに変換
List.ofArray([|1 .. 5|]) |> printfn "%A"

// Seqからリストに変換
List.ofSeq(seq{1 .. 5}) |> printfn "%A"

// trueになったものとfalseになったもの２つのリストに分ける
let partA, partB = cards |> List.partition(fun elm -> elm.Suit = "D" || elm.Suit = "H")
partA |> printfn "%A"
partB |> printfn "%A"

// インデックスを決める関数をぶつけて、並び替える(関数によって、取りうるインデックスの範囲を超えると死ぬ)
cardsA |> List.permute(fun index -> (index + 8) % List.length cardsA) |> printfn "%A"

// 条件に合う最初の要素を取り出す　なかったらKeyNotFoundException
cardsA |> List.pick(fun elm -> match elm with | {Number = 1; Suit = "D"; Write = "A"} -> Some elm | _ -> None) |> printfn "%A"


// 前の計算結果を引数としてもらってくる
//(((0+1)+2)+3) = 6
[1;2;3] |> List.reduce(fun acc elm -> acc + elm ) |> printfn "%A"

// 前の計算結果を引数としてもらってくる、後ろから
//(3 - (2 - (0 - 1))) 
//(3 - (2 - (-1))
//(3 - (2 + 1))
//(3 - 3)
//(0)
[1;2;3] |> List.reduceBack(fun elm acc -> acc - elm ) |> printfn "%A"

// 指定値でListを生成する
List.replicate 5 "rep" |> printfn "%A"

// リバース
[1;2;3;4;5] |> List.rev |> printfn "%A"

// foldは最終の結果だけ
// => 115
[1;2;3;4;5] |> List.fold (fun acc elm -> acc + elm) 100 |> printfn "%A"

// scanは履歴がlistで戻ってくる
//  => [100; 101; 103; 106; 110; 115]
[1;2;3;4;5] |> List.scan (fun acc elm -> acc + elm) 100 |> printfn "%A"

// scanを後ろから適用
// => [115; 114; 112; 109; 105; 100]
100 |> List.scanBack(fun acc elm -> acc + elm) [1;2;3;4;5] |> printfn "%A"

// compareを実装してたらいける
[-5;1;-6;7;-2;0] |> List.sort |> printfn "%A"

// 項目に１手間加える、あとはcompare任せ
[-5;1;-6;7;-2;0] |> List.sortBy(fun elm -> abs elm) |> printfn "%A"

// 条件を指定する(ここでは逆順を指定)
[-5;1;-6;7;-2;0] |> List.sortWith(fun elm1 elm2 -> if elm1 < elm2 then 1 else -1) |> printfn "%A"

// 合算(operator + を実装してる必要あり)
[1 .. 10] |> List.sum |> printfn "%d"

// 要素に１手間加えてから合算
[1 .. 10] |> List.sumBy(fun elm -> elm * 2) |> printfn "%d"

// 先頭を除いたリストを返却 Lispのcar
[1 .. 5] |> List.tail |> printfn "%A"

// Arrayに変換
[1 .. 5] |> List.toArray |> printfn "%A"

// Seqに変換
[1 .. 5] |> List.toSeq |> printfn "%A"

// truncate MSDNのリンク切れてて笑う
// 指定数以降の要素を切り捨てるみたい
[1 .. 5] |> List.truncate 3 |> printfn "%A"

// 見つけた要素を返す。なかったらNoneを返す
[1 .. 5] |> List.tryFind(fun elm -> elm = 3)|> printfn "%A"

// 見つかった要素の位置を返す。
[3 .. 59] |> List.tryFindIndex(fun elm -> elm = 59)|> printfn "%A"

// 指定した関数に一致する最初の要素を返す。
let odd elm = elm % 2 = 0
[1 .. 6] |> List.tryPick(fun elm -> if odd elm then Some elm else None )|> printfn "%A"

// ペアのリストを分解する
List.unzip [(1, 2);(3, 4)] |> printfn "%A"

// ペアのリストを分解する 2がないのがちょっときもい。命名するときもめたんじゃないだろうか
List.unzip3 [(1, 2, 3);(3, 4, 5)] |> printfn "%A"

// リストをくっつけてペアにする
List.zip [1;2] [3;4] |> printfn "%A"

// リストをくっつけてペアにする
List.zip3 [1;2] [3;4] [5;6]|> printfn "%A"
```