我从两组开始,abc和zxc。 "未修饰的"具有正确数量(1)的项目。
设置abc有两个项目,其中一个是未修改的项目
let unmodified = Set.intersect abc zxc
let newAndModified = a - unmodified
我希望newAndModified包含一个项目,但它有两个。它似乎与abc相同。
即使我的Set.intersect工作正常,其他Set函数也没有返回正确的结果,我相信我为这个对象实现CompareTo的方式有问题。
type Bar =
{ Id : int
Name : string
}
[<CustomEquality; CustomComparison>]
type Foo =
{ Name : string
Id : int
Bars : Bar list
}
override x.Equals(y) =
match y with
| :? Foo as y -> x.Id.Equals y.Id
&& x.Name.Equals y.Name
&& x.Bars.Head.Name.Equals y.Bars.Head.Name
| _ -> invalidArg "y" "cannot compare object to one that is not a Foo"
member x.CompareTo (y: obj) =
match y with
| null -> nullArg "y"
| :? Foo as y -> x.CompareTo(y)
| _ -> invalidArg "y" "Must be an instance of Foo"
member x.CompareTo (y: Foo) =
match x.Equals y with
| true -> 0
| false -> -1
interface IComparable<Foo> with
member x.CompareTo y = x.CompareTo y
interface System.IComparable with
member x.CompareTo y =
match y with
| :? Foo as y -> (x:> IComparable<_>).CompareTo y
| _ -> invalidArg "y" "cannot compare values of different types"
答案 0 :(得分:4)
您的CompareTo
实施绝对无法在此处运作。当两个对象相等(这是好的)时返回0,但如果它们不相等,则总是返回-1。这意味着第一个小于最后一个。
但是,这不会起作用。如果您有对象a
和b
,那么您的比较就是a < b
和b < a
(这违反了订购关系的要求)。
F#set要求对象是可订购的,因为它将数据保存在平衡树中(较小的元素位于左侧,较大的元素位于右侧) - 因此CompareTo
始终返回-1 ,它最终会创建一个毫无意义的树。
为什么要为该类型实现自定义比较?我想你这样做只是考虑一些领域而忽略其他领域。在这种情况下,您可以做一个很好的技巧,即创建一个包含您感兴趣的字段的元组,并在其上调用内置的hash
和compare
函数。例如:
compare (x.Id, x.Name, x.Bars.Head.Name)
(y.Id, y.Name, y.Bars.Head.Name)
这将使用元组的默认F#比较,这是一个正确定义的排序关系。