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

3

我有一组记录:

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;}]

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

2个回答

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

只需添加 IComparable 实现即可满足原帖作者的要求。 - kaefer
我曾考虑过这种方法,但似乎会使我在使用“人员记录”时的代码变得更加冗长。我喜欢尽可能地减少冗余。 - JDB
1
如果您不想放弃 F# 记录默认提供的结构相等性/结构比较,您需要将字段或整个记录包装在类或联合中,并对其实施自定义相等性/自定义比较。请参见例如 此问题 - kaefer

2
这是我目前所实现的,但可能有更好的方法。
我的解决方案是重写 People 记录上的 Equals 函数,以执行不区分大小写的比较。集合减法使用 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;}]

如果你知道更好的解决方案(代码更少),请发表评论而不是在这个答案下评论。我将非常乐意接受一个更简洁、更自然的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接