どうにもminByの挙動が不可解。
僕の理解が浅いだけなのか、それともissue投げるべきバグなのかがわからない・・・。
2019/12/27
バグじゃなくてそもそも使い方おかしいよ教えて頂きました!(コメント欄参照)
僕の使い方がおかしいだけでしたね
本当にありがとうございます!
対象のリスト
// トランプのカード
type Card =
{
// 値
Number : int
// 柄
Suit : string
// 表示上の数値(A,J,Q,K用)
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
minByする
minBy試す
// 最小値を取る、条件付き -> Cの1が取れるはずなんだが・・・
cards |> List.minBy(fun elm -> elm.Number = (List.min cards).Number && elm.Suit = "C" ) |> printfn "%A"
↓↓↓
実行結果
{Number = 13;
Suit = D;
Write = K}
!?
なんか想定と違うものが返ってきた。
maxByだと
maxByでやってみる
// C1が取れるよね
cards |> List.maxBy(fun elm -> elm.Number = (List.min cards).Number && elm.Suit = "C" ) |> printfn "%A"
↓↓↓
実行結果
{Number = 1;
Suit = C;
Write = A}
意図通り取れるんだよなぁ。
複数条件なのが悪い?
Numberだけ指定してみる
// Number=2を指定してるけどやっぱりminByだと取れない
cards |> List.minBy(fun elm -> elm.Number = 2 ) |> printfn "%A"
cards |> List.maxBy(fun elm -> elm.Number = 2 ) |> printfn "%A"
↓↓↓
実行結果
{Number = 13;
Suit = D;
Write = K}
{Number = 2;
Suit = H;
Write = 2}
Suitだけ指定してみる
// Suit="C"を指定してるけどやっぱりminByだと取れない
cards |> List.minBy(fun elm -> elm.Suit = "C" ) |> printfn "%A"
cards |> List.maxBy(fun elm -> elm.Suit = "C" ) |> printfn "%A"
↓↓↓
実行結果
{Number = 13;
Suit = D;
Write = K}
{Number = 1;
Suit = C;
Write = A}
謎
やっぱりmaxByはちゃんと絞れるけどminByは絞れてない感じ。
なんでやねん( ;∀;)
公式リポジトリらしきところで実装見ても、変な事してるようには見えないんだけどなぁ
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/list.fs
fsharp/list.fsから抜粋
[<CompiledName("MinBy")>]
let inline minBy projection (list:list<_>) =
match list with
| [] -> invalidArg "list" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
| h::t ->
let mutable acc = h
let mutable accv = projection h
for x in t do
let currv = projection x
if currv < accv then
acc <- x
accv <- currv
acc
[<CompiledName("MaxBy")>]
let inline maxBy projection (list:list<_>) =
match list with
| [] -> invalidArg "list" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
| h::t ->
let mutable acc = h
let mutable accv = projection h
for x in t do
let currv = projection x
if currv > accv then
acc <- x
accv <- currv
acc