Pratap D
Pratap D

Reputation: 321

How to compare the objects in 2 vectors in scala

I have 2 vectors defined with the below data: vector1 and vector2 are defined as Vector[Person] where a person can have both student and teacher records.

val v1 = """[
   {
      "category":"common",
      "type":"student",
      "roles":[
         {
            "name":"A",
            "type":"Type1"
         },
         {
            "name":"B",
            "type":"Type1"
         },
         {
            "name":"C",
            "type":"Type2"
         },
         {
            "name":"D",
            "type":"Type2"
         }
      ]
   }
]"""

val v2 = """[
   {
      "category":"common",
      "type":"student",
      "roles":[
         {
            "name":"A",
            "type":"Type1"
         },
         {
            "name":"B",
            "type":"Type1"
         },
         {
            "name":"C",
            "type":"Type2"
         },
         {
            "name":"D",
            "type":"Type2"
         }
      ]
   },
   {
      "type":"Teacher",
      "roles":[
         {
            "name":"AB",
            "type":"Type1"
         },
         {
            "name":"BC",
            "type":"Type1"
         },
         {
            "name":"CD",
            "type":"Type2"
         },
         {
            "name":"DE",
            "type":"Type2"
         }
      ]
   }
]"""

I need to compare both these vectors depending on an attribute i.e. type. This value can be student or teacher. If type is same then I should check for roles.

I tried using zipwithindex/indices but looks like only the elements in that index are compared. Is there a way that we can compare based on type from each element in vector. I want to declare both the vectors equal if type and roles are same.

Note: The above examples are jsons, and we read them into our case class

  case class Person(
      category: String,
      name: Option[String],
      `type`: Option[String],
      roles: List[Role]
  )

  case class Role(name: String, `type`: String)

and vector1/vector2 are read as Vector[Person]

Upvotes: 0

Views: 667

Answers (1)

vercadol
vercadol

Reputation: 21

When you create a case class, it has a bunch of methods implemented, one of them is the 'equals' method. It means that instances of the case class are not compared by reference, but by a structure ('equals' method simply compares all the attributes). When you want to compare by just some of the attributes while ignoring the others, you could try to override the 'equals' method (you could use simple == operator for comparison), BUT I don't recommend it. It would make your code confusing as the 'equal' function would not work as it's expected to.

For this purpose, I recommend writing a simple comparison function. If vectors have different sizes, they can't be equal. Otherwise you need the 'type' and 'roles' attributes to be the same. Role is a case class and it's equal method works exactly how we need to, so == operator is doing fine.

def personVectorsEqual(vec1 : Vector[Person], vec2 : Vector[Person]): Boolean ={
      if(vec1.size != vec2.size)
        false
      else (vec1, vec2).zipped.forall((p1, p2) => p1.`type` == p2.`type` && p1.roles == p2.roles)
}

Zipped method creates a sequence of tuples of objects that are on corresponding indices. We need to compare the objects in the tuples. As zipped method discards last elements of the longer sequence (when their sizes aren't equal), we need to ask for vectors' sizes explicitly.

Notes: Just be careful, do you really want to compare objects by an Option attribute? And in case there are just two types ("student" and "Teacher"), it would be clearer not to use String for them. Maybe try to have a look at enum or sealed traits/classes. Also, one of your json Persons miss the compulsory 'category.'

Upvotes: 1

Related Questions