2015-09-20 4 views
-1

Вот примеры, которые я играл с:заказ заказ в TreeMap

import collection.immutable.{TreeSet, TreeMap} 
    val ts = TreeSet(9, 23, 1, 2) 
    ts 
    val tm = TreeMap(3 -> "c", 1 -> "a", 2 -> "b") 
    tm 
    // convert a map to a sorted map 
    val m = Map("98" -> List(4, 12, 14), "001" -> List(22, 11)) 
    val t = TreeMap(m.toSeq: _*) 
    t // sorted by key 
    // sort an unsorted map 
    m.toSeq.sortWith((x, y) => x._2(0) < y._2(0)) 

    // add a unsorted map into a sorted map 
    val m1 = Map("07" -> List(3, 5, 1), "05" -> List(12, 5, 3)) 
    val t1: TreeMap[String, List[Int]] = t ++ m1 
    t1 // "001" is the first key 

я могу использовать sortWith на Map, чтобы получить пользовательский порядок, что, если я хочу использовать TreeMap, который использует другой порядок чем по умолчанию?

ответ

2

Вы не можете использовать значения Map, чтобы определить порядок по умолчанию для Карты.

TreeMap[A,B] «s конструктор принимает неявный Ordering[A] параметр, так что вы могли бы сделать что-то вроде этого:

// Will sort according to default Int ordering (ascending by numeric value) 
scala> val tm = TreeMap(3 -> "c", 1 -> "a", 2 -> "b") 
tm: scala.collection.immutable.TreeMap[Int,String] = Map(1 -> a, 2 -> b, 3 -> c) 

// A wild implicit appears! (orders descending by numeric value) 
scala> implicit val tmOrd = Ordering[Int].on((x:Int) => -x) 
tmOrd: scala.math.Ordering[Int] = [email protected] 

// Our implicit is implicitly (yeah) used by constructor 
scala> val invTm = TreeMap(3 -> "c", 1 -> "a", 2 -> "b") 
invTm: scala.collection.immutable.TreeMap[Int,String] = Map(3 -> c, 2 -> b, 1 -> a) 

Обратите внимание, что безопаснее ограничить сферу implicits, как этот. Если это возможно, вы должны построить (неявный) объект и передать его вручную или отделить область неявного объявления от того места, где на него может повлиять другой код.

Причина в том, что TreeMap построен на вершине дерева, которое использует значения ключей для поддержания структурных ограничений, которые позволяют эффективно считывать/записывать данные на основе ключей, что является основной целью Карты. Заказ на значения на карте просто не имеет смысла.

Обновление: Сложность логики заказа ничего не значит. По вашему комментарию:

scala> object ComplexOrdering extends Ordering[Int] { 
    | def compare(a: Int, b: Int) = { 
    |  if(a == 3) -1 else if(a == 2 * b) -1 else if(a == 3 * b) 0 else 1 
    | } 
    | } 
defined object ComplexOrdering 

scala> val tm = TreeMap(3 -> "c", 1 -> "a", 2 -> "b") 
tm: scala.collection.immutable.TreeMap[Int,String] = Map(1 -> a, 2 -> b, 3 -> c) 

scala> val tm = TreeMap(3 -> "c", 1 -> "a", 2 -> "b")(ComplexOrdering) 
tm: scala.collection.immutable.TreeMap[Int,String] = Map(3 -> c, 2 -> b, 1 -> a) 
+0

Что делать, если я хочу сортировать с более сложной функцией? Например: '(x: Int, y: Int) => {if (x == 3) -1 else if (x == 2 * y) -1 else if (x == 3 * y) 0 else 1 } '. – qed

+1

Пока вы сравниваете ключи, не имеет значения, насколько сложным является ваш заказ. Я покажу ответ, чтобы продемонстрировать это. – tkroman

1

TreeMap определяется как тип типа Map с заданным порядком его ключами. Это упорядочение определяется неявным параметром конструктора:

new TreeMap()(implicit ordering: Ordering[A]) // For TreeMap[A,B] 

так что вы можете установить альтернативный порядок на ключей при строительстве путем явного предоставления пользовательских Ordering[A].

Класс, однако, не предоставляет никаких (прямых) средств для установки заказа на основе значений . То, что у вас есть с вызовом .toSeq.sortWith, - это лучшее, что вы можете сделать, насколько мне известно, за исключением кодирования собственного типа коллекции.