José Villacreses
José Villacreses

Reputation: 177

TreeSet not respecting order after mapping

I don't know how to explain/understand the following behavior regarding TreeSet and the map function.

I think I'm missing a piece in the puzzle. Any light upon the matter will be very welcomed.

scala> class Person(val name: String, val age: Int) extends Ordered[Person]{
     |   def compare(that: Person) = {
     |     val nameComparison = name.compareToIgnoreCase(that.name)
     |     if(nameComparison != 0){
     |       nameComparison
     |     }else{
     |       age.compareTo(that.age)
     |     }
     |   }
     |   override def toString = s"$name || $age"
     | }
defined class Person

scala> import scala.collection.immutable.TreeSet
import scala.collection.immutable.TreeSet

scala> val tsPersons = TreeSet(
     |   new Person("Vivi", 31),
     |   new Person("ViVi", 4),
     |   new Person("vivi", 14)
     | )//1) printed in expected order
tsPersons: scala.collection.immutable.TreeSet[Person] = TreeSet(ViVi || 4, vivi || 14, Vivi || 31)

scala> tsPersons.map(p => p) //2) printed in expected order
res0: scala.collection.immutable.SortedSet[Person] = TreeSet(ViVi || 4, vivi || 14, Vivi || 31)

scala> tsPersons.map(p => (p.name, p.age)) //3) order messed up
res1: scala.collection.immutable.SortedSet[(String, Int)] = TreeSet((ViVi,4), (Vivi,31), (vivi,14))

scala> tsPersons.toList.map(p => (p.name, p.age)) //4) printed in expected order
res2: List[(String, Int)] = List((ViVi,4), (vivi,14), (Vivi,31))

In printing "1)" I can see tsPersons being sorted correctly.

In printings "2)" and "3)" the order of the elements for the map method is not consistent.

Finally, in printing "4)" with the toList method I can work on the correctly ordered List, so the map method on the list works fine with the same function literal p => (p.name, p.age) that didn't work before.

I'm sure there is something else I don't know about Sorted or TreeSet or map.

Thanks for your help in advance!

Upvotes: 2

Views: 318

Answers (1)

Aivean
Aivean

Reputation: 10882

If you understand how map for TreeSet works, you'll understand what is actually happening. Inside map new TreeSet is created and filled with transformed elements of original tree set. As new tree set will order new elements according to their own natural ordering, you get the messed result.

So, in second case you fill new tree set with Person elements and they are ordered respecting Person's compare method.

But in case #3 you get new TreeSet filled with tuples that are ordered according to tuple's ordering, which is ordering by first tuple's element with ties broken by second element.

In forth case you first convert your set to list, once again, inside toList new list builder is created and populated with elements from your original set preserving order (as List is ordered collection). So when you call map on list's elements, initial order is preserved (same for your tree set and list).

Hope this will help you to understand what's happening. If you still need some clarification, don't hesitate to ask.

Upvotes: 5

Related Questions