64

is there a way in Scala to sort an array of tuples using and arbitrary comparison function? In particular I need to sort and array of tuples by their second element, but I wanted to know a general technique to sort arrays of tuples.

Thanks!

7 Answers 7

140

In scala 2.8, there is a method sortBy. Here is a simple use case:

scala> val arr = Array(("One",1),("Two",2),("Four",4),("Three",3))
arr: Array[(java.lang.String, Int)] = Array((One,1), (Two,2), (Four,4), (Three,3))

scala> arr.sortBy(_._2)
res0: Array[(java.lang.String, Int)] = Array((One,1), (Two,2), (Three,3), (Four,4))

scala>
Sign up to request clarification or add additional context in comments.

4 Comments

2.8 is just plain cheating. +1
Gooood. I'll have to switch to 2.8 (currently using 2.7) Thanks
This does not sort in place, however.
@Daniel Yes, and I just wrote a post about it: old.nabble.com/…
26

You can use this code:

scala> val v = Array(('a', 2), ('b', 1))
v: Array[(Char, Int)] = Array((a,2), (b,1))

scala> scala.util.Sorting.stableSort(v,
     | (e1: (Char, Int), e2: (Char, Int)) => e1._2 < e2._2)

scala> v
res11: Array[(Char, Int)] = Array((b,1), (a,2))

Unfortunetly, it seems that Scala cannot infer the type of the array passed to stableSort. I hope that's ok for you.

2 Comments

Bit nicer: stableSort(v, (_._2 < _._2) : ((Char,Int),(Char,Int)) => Boolean) — keeps the concerns separate, and allows one to reason about the logic and the types as independent steps, especially since the inline type signature is only a nuisance here.
One things to note is that if you are dealing with the Any type in the sort column (suppose it has Long) you need to do: scala.util.Sorting.stableSort(v, (e1: (String, Any), e2: (String, Any)) => e1._2.asInstanceOf[Long] < e2._2.asInstanceOf[Long])
10

If it's an Array, it's probably typical to use in-place sorting algorithms. However, in idiomatic Scala code, mutable collections are usually not encouraged/used. If that's the case and you have am immutable collection (or would like to not modify the Array in place), use sortWith:

scala> val a = Array(1, 3, 2, 5)
a: Array[Int] = Array(1, 3, 2, 5)

scala> a.sortWith(_ > _)
res6: Array[Int] = Array(5, 3, 2, 1)

scala> a
res7: Array[Int] = Array(1, 3, 2, 5)

sorting an Array or any other collection of tuples:

scala> val a = Array(('a', 1), ('b', 4), ('c', 5), ('d', 2))
a: Array[(Char, Int)] = Array((a,1), (b,4), (c,5), (d,2))

scala> a.sortWith(_._2 > _._2)
res4: Array[(Char, Int)] = Array((c,5), (b,4), (d,2), (a,1))

scala> a
res5: Array[(Char, Int)] = Array((a,1), (b,4), (c,5), (d,2))

2 Comments

where can we find about about that "_._2" syntax? What is that called?
3

On Scala 2.8 (yes, again :), you can also do this:

val v = Array(('a', 2), ('b', 1))
scala.util.Sorting.stableSort(v)(manifest[(Char, Int)], Ordering.by(_._2))

In the specific case of pairs, this can also work to sort first by the second element, and then by the first:

scala.util.Sorting.stableSort(v)(manifest[(Char, Int)], Ordering.by(_.swap))

Comments

2

2.7 and not in place:

(Array((2,3), (4,2), (1,5)).toList.sort (_._2 < _._2)).toArray

Comments

1

You probably want def stableSort[K](a : Seq[K], f : (K, K) => Boolean) : Array[K] from scala.util.Sorting.
Your comparison function would be something like _._2 < _._1

Comments

1
val l = List((2, 1), (3, 2), (0, 3))
l sort { case(a, b) => a > b }

1 Comment

Problem is I have an Array :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.