2011-09-24 7 views
9

Dlaczego niezmienna wersja magazynu ListMap zapisuje się w porządku rosnącym, a wersja zmienna przechowuje w porządku malejącym?Dlaczego zmienne i niezmienne mapy listy mają różne porządki w Scali?

Oto test, który można użyć, jeśli masz scalatest-1.6.1.jar i JUnit-4.9.jar

@Test def StackoverflowQuestion() 
    { 
    val map = Map("A" -> 5, "B" -> 12, "C" -> 2, "D" -> 9, "E" -> 18) 
    val sortedIMMUTABLEMap = collection.immutable.ListMap[String, Int](map.toList.sortBy[Int](_._2): _*) 
    println("head : " + sortedIMMUTABLEMap.head._2) 
    println("last : " + sortedIMMUTABLEMap.last._2) 
    sortedIMMUTABLEMap.foreach(X => println(X)) 
    assert(sortedIMMUTABLEMap.head._2 < sortedIMMUTABLEMap.last._2) 

    val sortedMUTABLEMap = collection.mutable.ListMap[String, Int](map.toList.sortBy[Int](_._2): _*) 
    println("head : " + sortedMUTABLEMap.head._2) 
    println("last : " + sortedMUTABLEMap.last._2) 
    sortedMUTABLEMap.foreach(X => println(X)) 
    assert(sortedMUTABLEMap.head._2 > sortedMUTABLEMap.last._2) 
    } 

Herezje wyjście z testu Podania:

head : 2 
last : 18 
(C,2) 
(A,5) 
(D,9) 
(B,12) 
(E,18) 
head : 18 
last : 2 
(E,18) 
(B,12) 
(D,9) 
(A,5) 
(C,2) 
+2

Jedną z głównych korzyści z dobrej zbiorów API jest to, że chroni Cię od konieczności „wyczerpująco poznać wszystkie dziwactwa jak to". Kolejność iteracji nie jest częścią kontraktu 'ListMap', więc nigdy nie musisz o tym myśleć. –

+0

Mniej specyficzny opis interfejsu pozostawia więcej miejsca na przyszłe zmiany/ulepszenia. Jeśli chcesz zachować niezawodne zachowanie w zakresie kolejności elementów, użyj "SortedMap". – Raphael

+0

Dzięki posortowanej mapie działa dobrze dla mnie. – Zasz

Odpowiedz

12

objawy mogą być uproszczone do:

scala> collection.mutable.ListMap(1 -> "one", 2 -> "two").foreach(println) 
(2,two) 
(1,one) 

scala> collection.immutable.ListMap(1 -> "one", 2 -> "two").foreach(println) 
(1,one) 
(2,two) 

w „sortowanie” w kodzie nie jest sedno problemu, połączenie do ListMap używa wywołania ListMap.apply z obiektu towarzyszącego, który tworzy mapę listy wspieraną zmienną lub niezmienną listą. Zasadą jest, że zamówienie reklamowe zostanie zachowane.

Różnica wygląda na to, że zmienna lista jest chroniona przez listę niezmienną , a wstawianie odbywa się z przodu. Dlatego właśnie podczas iteracji uzyskujesz zachowanie LIFO. Wciąż spoglądam na niezmienny, ale założę się, że wkładki są skutecznie z tyłu. Edycja, zmieniam zdanie: wstawienie jest prawdopodobnie z przodu, ale wygląda na to, że metoda immutable.ListMap.iterator postanawia odwrócić wynik z toList.reverseIterator na zwróconym iteratorze. Myślę, że warto go sprowadzić na listę mailingową.

Czy dokumentacja może być lepsza? Na pewno. Czy jest ból? Niezupełnie, nie pozwalam na to. Jeśli dokumentacja jest niekompletna, dobrze jest przetestować zachowanie lub sprawdzić źródło przed wybieraniem struktury w stosunku do innej.

W rzeczywistości może pojawić się ból, jeśli zespół Scala zdecyduje się zmienić zachowanie w późniejszym czasie i poczuje, że może, ponieważ zachowanie jest skutecznie nieudokumentowane i nie ma umowy.


Aby rozwiązać swój przypadek użycia wyjaśniono w komentarzu, powiedzmy zbierzesz liczbę częstotliwości ciąg w mapie (zmienny lub stały):

val map = Map("A" -> 5, "B" -> 12, "C" -> 2, "D" -> 9, "E" -> 18, "B" -> 5) 

Ponieważ trzeba tylko rozwiązać raz na koniec, można konwertować krotki z mapy do seq a następnie sortowania:

map.toSeq.sortBy(_._2) 
// Seq[(java.lang.String, Int)] = ArrayBuffer((C,2), (A,5), (B,5), (D,9), (E,18)) 
+0

Dobrze, będzie trochę problem, jeśli zmienią rzeczy teraz (lub później). Zauważyłem, że bardzo trudno jest debugować, ponieważ mój test sortowania i źródło miały dokładnie ten sam kod, ale różne wersje ListMap. Byłoby znacznie lepiej, gdyby kolekcje miały lepsze nazwy reprezentujące ich zmienność – Zasz

+0

Zaznaczę tę odpowiedź jako poprawną, jeśli możesz zasugerować, jakiej struktury danych powinienem użyć, potrzebuję posortowanej tabeli (string, int) par posortowanych według wartości int, i ITERABLE po sortowaniu. – Zasz

+0

@Zasz, pozwalasz na duplikaty lub wiele ciągów dla tego samego int w twojej tabeli? Czy chcesz, aby stół został posortowany, ponieważ jest zmutowany? Lub jest w porządku, jeśli sortujesz go przed wyświetlaniem/iterowaniem? Nie zaakceptowałbym mojej odpowiedzi, dopóki nie otrzymam odpowiedzi z listy mailingowej ... – huynhjl

4

Jak widzę go ani ListMap roszczeń być sortowane map, tylko mapa zaimplementowane z Listą. W rzeczywistości nie widzę niczego w ich umowie, która mówi cokolwiek o zachowaniu zamówienia reklamowego.

Programowanie w Scali wyjaśnia, że ​​ListMap może być przydatna, jeśli wczesne elementy są bardziej dostępne, ale w przeciwnym razie ma niewielką przewagę nad Mapą.

+1

Dokładnie to, co miałem na myśli, mówiąc o niewystarczającej ilości informacji na temat struktur danych. Jak wylądowałem wybierając ListMap był po obejrzeniu wątku w stackoverflow, który użył go do sortowania. I w oparciu o to, co jest napisane dla dokumentacji ListMap, bardzo trudno jest wiedzieć, gdzie użyć ListMap – Zasz

1

Nie buduj żadnych oczekiwań na zamówienie, nie jest zadeklarowany i będzie się różnić między wersjami Scala.

Na przykład

import scala.collection.mutable.{ListMap => MutableListMap} 

MutableListMap("A" -> 5, "B" -> 12, "C" -> 2, "D" -> 9, "E" -> 18).foreach(println) 

na 2,9.1 zawiera: (E 18) (D, 9) (C-2) (B, 12) (A, 5)

ale 2.11.6 otrzymujemy: (E 18) (C, 2) (a, 5) (B 12) (D, 9)

Powiązane problemy