Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TreeMap.zipWithIndex loses the TreeMap's custom ordering #10146

Closed
scabug opened this issue Jan 12, 2017 · 10 comments
Closed

TreeMap.zipWithIndex loses the TreeMap's custom ordering #10146

scabug opened this issue Jan 12, 2017 · 10 comments

Comments

@scabug
Copy link

scabug commented Jan 12, 2017

When one uses zipWithIndex on a TreeMap, and the latter was created using a non-default ordering, the resulting map again receives the default ordering (coming from the implicit parameter).

The result is something unexpected, from the point of view of the end user: the map's ordering is suddenly lost. An artificial example from REPL which illustrates the issue.

scala> val reversedIntOrdering = implicitly[Ordering[Int]].reverse
reversedIntOrdering: scala.math.Ordering[Int] = scala.math.Ordering$$anon$4@2e38d44e

scala> val treeMap = TreeMap(2 -> "a", 3 -> "b", 4 -> "c", 5 -> "d")(reversedIntOrdering)
treeMap: scala.collection.immutable.TreeMap[Int,String] = Map(5 -> d, 4 -> c, 3 -> b, 2 -> a)

scala> treeMap.zipWithIndex.foreach(println)
((2,a),3)
((3,b),2)
((4,c),1)
((5,d),0)

What is even funnier, if the map loses its TreeMap type, the result is "regular" again:

scala> val anyMap: Map[Int, String] = treeMap
anyMap: Map[Int,String] = Map(5 -> d, 4 -> c, 3 -> b, 2 -> a)

scala> anyMap.zipWithIndex.foreach(println)
((5,d),0)
((4,c),1)
((3,b),2)
((2,a),3)
@scabug
Copy link
Author

scabug commented Jan 12, 2017

Imported From: https://issues.scala-lang.org/browse/SI-10146?orig=1
Reporter: Maxim Buzdalov (MaxBuzz)
Affected Versions: 2.12.1

@scabug
Copy link
Author

scabug commented Jan 13, 2017

@som-snytt said:
The last effect is due to the special maps of unusual size, which are different from ROUSes.

scala> val m = TreeMap((0 to 3).map(i => (i, ('a'+i).toChar)): _*)(reversedIntOrdering)
m: scala.collection.immutable.TreeMap[Int,Char] = Map(3 -> d, 2 -> c, 1 -> b, 0 -> a)

scala> (m: Map[Int,Char]).zipWithIndex
res0: scala.collection.immutable.Map[(Int, Char),Int] = Map((3,d) -> 0, (2,c) -> 1, (1,b) -> 2, (0,a) -> 3)

scala> val m = TreeMap((0 to 4).map(i => (i, ('a'+i).toChar)): _*)(reversedIntOrdering)
m: scala.collection.immutable.TreeMap[Int,Char] = Map(4 -> e, 3 -> d, 2 -> c, 1 -> b, 0 -> a)

scala> (m: Map[Int,Char]).zipWithIndex
res1: scala.collection.immutable.Map[(Int, Char),Int] = Map((2,c) -> 2, (4,e) -> 0, (0,a) -> 4, (3,d) -> 1, (1,b) -> 3)

@magnolia-k
Copy link

In Scala 2.13.0

Welcome to Scala 2.13.0 (OpenJDK 64-Bit Server VM, Java 12.0.1).
Type in expressions for evaluation. Or try :help.

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> val reversedIntOrdering = implicitly[Ordering[Int]].reverse
reversedIntOrdering: scala.math.Ordering[Int] = scala.math.Ordering$Reverse@3bf3e060

scala> val treeMap = TreeMap(2 -> "a", 3 -> "b", 4 -> "c", 5 -> "d")(reversedIntOrdering)
treeMap: scala.collection.immutable.TreeMap[Int,String] = TreeMap(5 -> d, 4 -> c, 3 -> b, 2 -> a)

scala> treeMap.zipWithIndex.foreach(println)
((5,d),0)
((4,c),1)
((3,b),2)
((2,a),3)

@Jasper-M
Copy link
Member

Jasper-M commented Aug 5, 2019

I don't see how the map could keep its non-default ordering, since the type of the key changes.
Note that in 2.13 the result of zipWithIndex is an Iterable and not a TreeMap.

@magnolia-k
Copy link

@Jasper-M
I'm sorry, but I didn't understand what the comment meant.
Do you claim that you can't reach the reason for this behavior in Scala 2.13.0?

@SethTisue
Copy link
Member

SethTisue commented Aug 25, 2023

I'm also puzzled by Jasper's remark, in the context of 2.13. If we're returning an Iterable now, then surely we could have it be ordered any way we want, including order-preserving? @scala/collections

@SethTisue SethTisue added this to the Backlog milestone Aug 25, 2023
@som-snytt
Copy link

som-snytt commented Aug 26, 2023

The previous comment was about 2.12. The signature changed for 2.13, which apparently was a long time ago now.

This is a regression:

scala 2.13.11> import collection.immutable, immutable.TreeMap, immutable.SortedSet
import collection.immutable
import immutable.TreeMap
import immutable.SortedSet

scala 2.13.11> val reversedIntOrdering = implicitly[Ordering[Int]].reverse
val reversedIntOrdering: scala.math.Ordering[Int] = scala.math.Ordering$Reverse@4e29d137

scala 2.13.11> val s = immutable.SortedSet(10.to(20).toList:_*)(reversedIntOrdering)
val s: scala.collection.immutable.SortedSet[Int] = TreeSet(20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10)

scala 2.13.11> s.zipWithIndex.take(5)
val res0: scala.collection.immutable.Set[(Int, Int)] = HashSet((17,3), (10,10), (15,5), (16,4), (20,0))

Also to note we'd normally use lazyZip, as a reminder to self.

@SethTisue SethTisue modified the milestones: Backlog, 2.13.0 Aug 26, 2023
@SethTisue
Copy link
Member

SethTisue commented Aug 26, 2023

Eh? Jasper's comment directly references 2.13.

In any case, the 2.13 ordering is as desired, so we should close this, I think. @som-snytt but feel free to open a new ticket with your new, somewhat different case

@som-snytt
Copy link

som-snytt commented Aug 26, 2023

OK. I thought the fix would be similar for sorted things, but the map case requires defining that the result keeps iteration order.

Edit: I fixed my comment, as the signature on SortedSet changed from returning SortedSet (but naturally ordered) to Set. That says that the library is not attempting to maintain order even when it can, IIUC. (I'm about to fall asleep, so maybe this doesn't make sense.)

I read or misread the comment as "impossible in 2.12, but note in 2.13 the signature changed". But neither here nor there.

Neither hair nor Nair. (Saving that for later.)

@Jasper-M
Copy link
Member

Jasper-M commented Aug 28, 2023

impossible in 2.12, but note in 2.13 the signature changed

Hard to be sure after 4 years, but I think this is what I meant. As in, note that in 2.13 the ordering is as desired because the resulting collection doesn't have a scala.math.Ordering anymore, so that isn't portable to 2.12.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants