Scala: group by equivalence relation

112 views Asked by At

I have a List[String]. I want to group it by a given equivalence relation:

def f(x: String, y: String): Boolean = {
  if (x == "" || y == "") {
    false
  } else {
    x == y
  }
}

I have tried method groupBy, but I cannot achieve empty strings to be in separate groups.

I would prefer the answer for any equivalence relation f(x: String, y: String): Boolean, not just this one.

EDIT: I have not specified, but the input type is really List[String], not List[(String, String)], f is a binary relation, that's why it has 2 String inputs, and expected return type is List[List[String]]

EDIT: As @andrey-tyukin mentioned, f is not an equivalence relation, so requesting "answer for any equivalence relation" is nonsense.

EDIT: An example:

Input: List("a", "a", "b", "", "")
Output: List(List("a", "a"), List("b"), List(""), List(""))
  • "a" == "a", that's why they go in the same group
  • Although "" == "", but f would result in false, so they are not in the same group
3

There are 3 answers

0
talex On

groupBy partitioning by value, not by relation.

You need a function that will map your any equivalent object to same value.

0
esse On

How about this:

val strs = List("a", "", "b", "c", "", "a", "a", "c")
val grps = strs.sorted.foldLeft(Nil: List[List[String]]){ 
  case (h::tl, s) if h.head == s && s.nonEmpty => (s::h) :: tl 
  case (r, s) => List(s) :: r 
}
0
counter2015 On

I'm not sure what you want, it seems like your data is List[(String, String)]?

If so, you can try this

def f(x: String, y: String): Boolean = {
  if (x == "" || y == "") {
    false
  } else {
    x == y
  }
}

val xs = List(("", ""), ("", "1"), ("1", "1"), ("1", "2"))

val res = xs.groupBy((f _).tupled)
println(res)
// Map(false -> List((,), (,1), (1,2)), true -> List((1,1)))