使用不区分大小写的比较从集合中减去记录

时间:2014-02-17 21:19:19

标签: f# record string-comparison

我有一组记录:

type Person =
    {
        Name : string
        Age : int
    }


let oldPeople =
    set [ { Name = "The Doctor"; Age = 1500 };
          { Name = "Yoda";       Age = 900 } ]

与上面的硬编码示例不同,数据集实际上来自数据源(我几乎无法控制)。现在我需要从另一个数据源中减去一组数据。一般来说,第二个来源中的数据匹配,但偶尔会有资本化的差异:

let peopleWhoAreConfusedAboutTheirAge =
    set [ { Name = "THE DOCTOR"; Age = 1500 } ]

当我尝试从第一个集合中减去第二个集合时,它会失败,因为字符串比较区分大小写:

let peopleWhoKnowHowOldTheyAre =
    oldPeople - peopleWhoAreConfusedAboutTheirAge
val peopleWhoKnowHowOldTheyAre : Set<Person> =
  set [{Name = "The Doctor";
        Age = 1500;}; {Name = "Yoda";
                       Age = 900;}]

有没有办法对Name记录的People字段执行不区分大小写的比较?

2 个答案:

答案 0 :(得分:2)

这是我到目前为止所实现的,尽管可能有更好的方法。

我的解决方案是覆盖Equals记录上的People函数,以便执行不区分大小写的比较。设置减法使用Equals函数来确定两个记录是否彼此匹配。通过覆盖Equals,我被迫(通过警告和错误)覆盖GetHashCode并实施IComparable(以及设置CustomEqualityCustomComparison属性) :

[<CustomEquality; CustomComparison>]
type Person =
    {
        Name : string
        Age : int
    }

    member private this._internalId =
        this.Name.ToLower() + this.Age.ToString()

    interface System.IComparable with
        member this.CompareTo obj =
            let other : Person = downcast obj
            this._internalId.CompareTo( other._internalId )

    override this.Equals( other ) =
        match other with
        | :? Person as other -> 
            System.String.Compare( this._internalId, other._internalId ) = 0
        | _ -> false

    override this.GetHashCode() =
        this._internalId.GetHashCode()
然而,这似乎可以解决问题:

let oldPeople =
    set [ { Name = "The Doctor"; Age = 1500 };
          { Name = "Yoda";       Age = 900 } ]

let peopleWhoAreConfusedAboutTheirAge =
    set [ { Name = "THE DOCTOR"; Age = 1500 } ]

let peopleWhoKnowHowOldTheyAre =
    oldPeople - peopleWhoAreConfusedAboutTheirAge
val peopleWhoKnowHowOldTheyAre : Set<Person> = set [{Name = "Yoda";
                                                     Age = 900;}]

如果你知道一个更好的解决方案(涉及更少的代码),请发布它而不是评论这个答案。我很乐意接受一个不那么冗长,尴尬的解决方案。

答案 1 :(得分:2)

这是另一种方法:

type Name(value) =
  member val Value = value
  override this.Equals(that) =
    match that with 
    | :? Name as name -> StringComparer.CurrentCultureIgnoreCase.Equals(this.Value, name.Value)
    | _ -> false
  override this.GetHashCode() =
    StringComparer.CurrentCultureIgnoreCase.GetHashCode(this.Value)

type Person =
  {
    Name: Name
    Age: int
  }

{Name=Name("John"); Age=21} = {Name=Name("john"); Age=21} //true