4

私はトイプロブレム(凸包の識別)で遊んでいて、辞書式順序付けがすでに2回必要でした。ケースの1つにリストが表示type Point = { X: float; Y: float }されました。X座標で並べ替え、等しい場合はY座標で並べ替えます。
私は次のように書くことになりました:

let rec lexiCompare comparers a b =
   match comparers with
   [ ] -> 0
   | head :: tail -> 
      if not (head a b = 0) then head a b else
      lexiCompare tail a b 

let xComparer p1 p2 = 
   if p1.X > p2.X then 1 else
   if p1.X < p2.X then -1 else
   0

let yComparer p1 p2 = 
   if p1.Y > p2.Y then 1 else
   if p1.Y < p2.Y then -1 else
   0

let coordCompare =
   lexiCompare [ yComparer; xComparer ]

それは私がすることを可能にします

let lowest (points: Point list) =
   List.sortWith coordCompare points 
   |> List.head

ここまでは順調ですね。ただし、これは少し手間がかかります。-1、0、または1を返す特定の比較子を作成する必要がありますが、これまでのところ、List.minByのような場合にこれを使用する簡単な方法はわかりません。理想的には、比較できる関数のリストを提供するという方針に沿って何かを行い([(fun p-> pX);(fun p-> pY)]など)、リストの辞書式最小値のようなことを行いたいと思います。その機能のリストをサポートするアイテムの。

F#でこれを実現する方法はありますか?それとも私はこれについて間違って考えていますか?

4

3 に答える 3

3

まず、F#の組み込みcompare関数を利用できます。

let xComparer p1 p2 = compare p1.X p2.X
let yComparer p1 p2 = compare p1.Y p2.Y

または、必要に応じて、これを少し明確に抽象化することもできます。

let compareWith f a b = compare (f a) (f b)
let xComparer = compareWith (fun p -> p.X)
let yComparer = compareWith (fun p -> p.Y)

または、ご存知のように、このアプローチをリスト処理関数に直接組み込むことができます。

let rec lexiCompareWith l a b =
    match l with
    | [] -> 0
    | f::fs ->
        match compare (f a) (f b) with
        | 0 -> lexiCompareWith fs a b
        | n -> n

ここでの重要な制限の1つは、それらをリストに入れるため、関数はすべて同じ戻りタイプを持っている必要があるということです。これはあなたのPoint例では問題ではありませんが(両方の関数にタイプPoint -> floatがあるため)、2つのPersonオブジェクトを名前で並べ替えてから年齢で並べ替えることができなくなります(最初のプロジェクションにはタイプPerson -> stringがあり、2番目のプロジェクションにはタイプがあるためPerson -> int)。

于 2012-04-07T03:12:59.210 に答える
3

F#でこれを実現する方法はありますか?それとも私はこれについて間違って考えていますか?

F#は、次のようなレコードタイプを定義すると、これを自動的に実行します。

> type Point = { X: float; Y: float };;
type Point =
  {X: float;
   Y: float;}

すぐに値の比較を開始できます。たとえば、ポイントの3要素リストを定義し、組み込みのList.sort:を使用して辞書式順序に並べ替えます。

> [ { X = 2.0; Y = 3.0 }
    { X = 2.0; Y = 2.0 }
    { X = 1.0; Y = 3.0 } ]
  |> List.sort;;
val it : Point list = [{X = 1.0;
                        Y = 3.0;}; {X = 2.0;
                                    Y = 2.0;}; {X = 2.0;
                                                Y = 3.0;}]

X結果は最初に。でソートされ、次に。でソートされていることに注意してくださいY

compare組み込み関数を使用して、同等のタイプの2つの値を比較できます。

カスタムオーダーを使用する場合は、2つのオプションがあります。カスタム全順序を使用してすべての操作を実行する場合は、andfriendsの実装としてタイプ定義に属しIComparableます。List.sortByいくつかの操作にカスタム順序を使用する場合は、やなどの高階関数を使用できますList.sortWith。たとえば、 F#は2タプルの辞書式比較を生成するため、List.sortBy (fun p -> p.Y, p.X)並べ替えてYから並べ替えXます(!)。

これはF#の大きな利点の1つです。

于 2012-04-09T12:19:09.217 に答える
2

私はあなたの質問を正しく理解していないと思いますが、次のコードはうまく機能しませんか?

let lowest (points : Point list) = List.sort points |> List.head

F#はレコードデータ型に対して暗黙的な比較を実行しているようです。そして、私の小さな実験は、比較がたまたま辞書式であることを示しています。しかし、その結果を裏付ける証拠は見つかりませんでした。

したがって、F#がレコードを辞書式に比較するかどうかはまだわかりません。代わりにタプルを使用して、次のように書くことができます。

let lowest (points : Point list) =
    let tuple = List.map (fun pt -> (pt.X, pt.Y)) points |> List.sort |> List.head
    { X = fst tuple; Y = snd tuple }

この投稿がお役に立てば幸いです。

于 2012-04-07T14:18:18.420 に答える