Hash 实现区分联合类型的快速CustomEquality和CustomComparison
对于使用键引用某些坐标,我希望使用区分的联合类型,因为它们允许各种类型的有效模式匹配 考虑以下代码snipet:Hash 实现区分联合类型的快速CustomEquality和CustomComparison,hash,f#,pattern-matching,equality,discriminated-union,Hash,F#,Pattern Matching,Equality,Discriminated Union,对于使用键引用某些坐标,我希望使用区分的联合类型,因为它们允许各种类型的有效模式匹配 考虑以下代码snipet: [<CustomEquality; CustomComparison>] type Coord = | Spot of AssetKey | Vol of AssetKey * DateTime option | Rate of Currency ..... member this.sor
[<CustomEquality; CustomComparison>]
type Coord =
| Spot of AssetKey
| Vol of AssetKey * DateTime option
| Rate of Currency
.....
member this.sortKey =
match this with
| Spot(key) -> (0 , key.toString)
| Vol(key) -> (1 , key.toString)
| Vol(key, Some(t)) -> (2 , key.toString + t.ToShortString())
| Rate(cur) -> (3 , cur.toString)
......
interface IComparable with
member this.CompareTo(obj) =
match obj with
| :? Coord as other -> compare this.sortKey other.sortKey
| _ -> invalidArg "obj" "not a Coord type"
override this.Equals(obj) =
match obj with
| :? Coord as other -> this.sortKey = other.sortKey
| _ -> false
override this.GetHashCode() = this.sortKey.GetHashCode()
另一种表现良好的方法是什么?在我的一些计时中,sortKey功能会损失30%甚至更多的整体性能
谢谢你的建议和改进 简单优化
您可以轻松完成的一个基本优化是,当您可以仅根据
Coord
的类型做出决策时,避免调用toString
。您可以编写以下内容,而不是构建sortKey
:
// Separate functions that return tag and key, so that we don't
// have to call 'toString' if we can decide based just on the Tag
member this.Tag =
match this with
| Spot _ -> 0 | Vol(_, None) -> 1
| Vol _ -> 2 | Rate _ -> 3
member this.Key =
match this with
| Spot(key) | Vol(key, None) -> key.toString | Rate cur -> cur.toString
| Vol(key, Some t) -> key.toString + t.ToShortString())
interface IComparable with
member this.CompareTo(obj) =
match obj with
| :? Coord as other ->
let c = compare this.Tag other.Tag
// Try comparing based on the tag first - if the tags
// are the same, then get Key and compare based on the key
if c <> 0 then c else compare this.Key other.Key
| _ -> invalidArg "obj" "not a Coord type"
给定类型为AssetKey
的值,您现在可以编写k.Key
来获取缓存的字符串表示形式,并可以使用活动模式对其进行模式匹配:
match k with
| Equity k -> ...
| EquityIndex i -> ...
你可以考虑做一些像之类的事情。
type CoordRepr =
| Spot of AssetKey
| Vol of AssetKey * DateTime option
| Rate of Currency
let sortKey = function
| Spot(key) -> 1,key.ToString()
| Vol(key,None) -> 2,key.ToString()
| Vol(key,Some(v)) -> 2,key.ToString() + v.ToShortDateString()
| Rate(key) -> 3,key.ToString()
type Coord(repr) =
let sortKey = sortKey repr
member __.Repr = repr
member __.SortKey = sortKey
override __.Equals(that) =
match that with
| :? Coord as c -> sortKey = c.SortKey
| _ -> false
override __.GetHashCode() = sortKey.GetHashCode()
interface System.IComparable with
member __.CompareTo(that) =
match that with
| :? Coord as c -> compare sortKey c.SortKey
| _ -> failwith "invalidArg"
let Spot k = Coord(Spot k)
let Vol(k,v) = Coord(Vol(k,v))
let Rate(k) = Coord(Rate(k))
let (|Spot|Vol|Rate|) (c:Coord) =
match c.Repr with
| Spot k -> Spot k
| Vol(k,v) -> Vol(k,v)
| Rate k -> Rate k
然后使用签名文件隐藏
CoordRepr
,Coord
的构造函数,sortKey
,等等。谢谢您的帮助。我实现了第一个版本,速度快了大约100倍。以下是我的实现:
// This type will not be used directly - it is an internal implementation
// hidden from the users that will be accessed using active patterns
[<RequiresQualifiedAccess>]
type AssetKeyInternal =
| Equity of string
| EquityIndex of string
override x.ToString() = ...
// Public type with active patterns for pattern matching
type AssetKey(key:AssteKeyInternal) =
let str = lazy key.ToString() // Lazily cached string
member x.Key = str.Value // Evaluated when accessed for the first time
member x.Value = key // Returns the internal representation
// Define active patterns working over AssetKey type
let (|Equity|EquityIndex|) (k:AssetKey) =
match k.Value with
| AssetKeyInternal.Equity(e) -> Equity(e)
| AssetKeyInternal.EquityIndex(e) -> EquityIndex(e)
match k with
| Equity k -> ...
| EquityIndex i -> ...
type CoordRepr =
| Spot of AssetKey
| Vol of AssetKey * DateTime option
| Rate of Currency
let sortKey = function
| Spot(key) -> 1,key.ToString()
| Vol(key,None) -> 2,key.ToString()
| Vol(key,Some(v)) -> 2,key.ToString() + v.ToShortDateString()
| Rate(key) -> 3,key.ToString()
type Coord(repr) =
let sortKey = sortKey repr
member __.Repr = repr
member __.SortKey = sortKey
override __.Equals(that) =
match that with
| :? Coord as c -> sortKey = c.SortKey
| _ -> false
override __.GetHashCode() = sortKey.GetHashCode()
interface System.IComparable with
member __.CompareTo(that) =
match that with
| :? Coord as c -> compare sortKey c.SortKey
| _ -> failwith "invalidArg"
let Spot k = Coord(Spot k)
let Vol(k,v) = Coord(Vol(k,v))
let Rate(k) = Coord(Rate(k))
let (|Spot|Vol|Rate|) (c:Coord) =
match c.Repr with
| Spot k -> Spot k
| Vol(k,v) -> Vol(k,v)
| Rate k -> Rate k