我有一个代表Person的案例类。
case class Person(firstName: String, lastName: String)
我需要以不区分大小写的方式根据名字和姓氏进行人物比较,例如:
Person("John", "Doe") == Person("john", "Doe") // should return true
或在Seq中
Seq(Person("John", "Doe")).contains(Person("john", "Doe")
最简单的方法是在Person case类中覆盖equals和hashCode方法,但是如果在类的情况下不能覆盖equals和hashCode,那么以干净的方式执行此操作的最佳方法是什么。
有人可以推荐一种解决这种区分大小写问题的惯用方法吗?
谢谢, Suriyanto
答案 0 :(得分:2)
对于案例类,我不会 $resultsall = array_map(function ($json) { return json_decode($json, true); }, $res);
,equals
的原始含义,因此,hashCode
。==
从功能编程的角度来看,恕我直言这里最惯用的解决方案是使用类型类:
case class Person(firstName: String, lastName: String)
trait Equal[A] {
def eq(a1: A, a2: A): Boolean
}
object Equal {
def areEqual[A : Equal](a1: A, a2: A): Boolean = implicitly[Equal[A]].eq(a1, a2)
implicit object PersonEqual extends Equal[Person] {
override def eq(a1: Person, a2: Person): Boolean = a1.firstName.equalsIgnoreCase(a2.firstName) &&
a1.lastName.equalsIgnoreCase(a2.lastName)
}
}
在REPL会话中:
scala> import Equal.areEqual
import Equal.areEqual
scala> val p1 = Person("John", "Doe")
p1: Person = Person(John,Doe)
scala> val p2 = p1.copy(firstName = "john")
p2: Person = Person(john,Doe)
scala> areEqual(p1, p2)
res0: Boolean = true
scala> val p3 = p1.copy(lastName = "Brown")
p3: Person = Person(John,Brown)
scala> areEqual(p1, p3)
res1: Boolean = false
这样,如果您需要在给定的上下文中为Person
提供不同的相等含义,则可以实现Equal[Person]
的版本而不触及任何其他内容。例如:在代码的给定点,如果它们具有相同的姓氏,则两个Person
个实例是相等的:
implicit object PersonLastnameEqual extends Equal[Person] {
override def eq(a1: Person, a2: Person): Boolean = a1.lastName.equalsIgnoreCase(a2.lastName)
}
REPL会议:
scala> val p1 = Person("John", "Doe")
p1: Person = Person(John,Doe)
scala> val p2 = p1.copy(firstName = "Mary")
p2: Person = Person(Mary,Doe)
scala> areEqual(p1, p2)
res0: Boolean = true
答案 1 :(得分:1)
你可以执行一些"规范化"在人员建设:
sealed trait Person {
def firstName:String
def lastName:String
}
object Person {
def apply(firstName:String, lastName:String):Person = PersonNormalized(firstName.toLowerCase, lastName.toLowerCase)
private case class PersonNormalized(firstName:String, lastName:String) extends Person
}
由您决定是否优于覆盖equals和hashCode
答案 2 :(得分:1)
最简单的方法是覆盖Person case类中的equals和hashCode方法,但是如果类不满意则重写equals和hashCode
如果您的实施符合the contract,则覆盖它们是完全可以接受的。唯一的问题是,如果Person
发生变化,则需要更新,但其他解决方案也是如此。
答案 3 :(得分:0)
创建普通类(不是case
)并为其编写equals
/ hashcode
。 IDE-s通常会得到一些片段(因为它们在Java中是必需的)。
class Person(val firstName: String, val lastName: String) {
override def hashCode = ???
override def equals = ???
}
或者,如果我们要解决“XY问题”,您应该写出更广泛的关注/目标。也许,实际上,您应该只有Map
和case class
- 仅使用较低的名称,或者在DB中使用Long
令牌。猜猜......
答案 4 :(得分:0)
对于.nojekyll
的所有成员的不区分大小写的比较,考虑其值的(较低的)字符串,如下所示,
Person
因此
case class Person(firstName: String, lastName: String) {
def ==(that: Person) = {
val thisStr = this.productIterator.mkString.toLowerCase
val thatStr = that.productIterator.mkString.toLowerCase
thisStr == thatStr
}
}
答案 5 :(得分:0)
我不建议为案例类更改==
的功能,但您可以创建一个具有不区分大小写比较含义的新运算符:
case class Person(firstName: String, lastName: String) {
def toUpper =
this.copy(firstName = firstName.toUpperCase, lastName = lastName.toUpperCase)
def =~=(that: Person) = this.toUpper == that.toUpper
}
Person("john", "smith") =~= Person("JoHn", "SmiTH") //true
Seq(
Person("JoHn", "SmiTH"),
Person("Jack", "Jones")
).exists(_ =~= Person("john", "smith")) //true
如果您想要比.exists
更具体的内容:
implicit class PersonSeq(s: Seq[Person]) {
def containsInsensitive(p: Person) = s.exists(_ =~= p)
}
Seq(
Person("JoHn", "SmiTH"),
Person("Jack", "Jones")
).containsInsensitive(Person("john", "smith"))
答案 6 :(得分:0)
另一种使用字符串插值的方法(参见https://stackoverflow.com/a/28445089/471136):
implicit class StringInterpolations(sc: StringContext) {
def ci = new {
def unapply(other: String) = sc.parts.mkString.equalsIgnoreCase(other)
}
}
"Hello" match {
case ci"Bye" => println("bad!")
case ci"HELLO" => println("sweet!")
case _ => println("fail!")
}
Person("John", "Doe") match {
case Person(ci"john", ci"Doe") =>
case _ => assert(false)
}