2012-12-23 16 views
17

Dla listy Scala [Int] Mogę wywołać metodę max, aby znaleźć maksymalną wartość elementu.Jak mogę znaleźć indeks maksymalnej wartości na liście w Scali?

Jak mogę znaleźć indeks maksymalnego elementu?

To, co robię teraz:

val max = list.max 
val index = list.indexOf(max) 
+0

brzmi jak dziwny przypadek użycia. może trzeba użyć posortowanej struktury danych? – andyczerwonka

+0

Tak, masz rację co do dziwnego przypadku użycia, możesz powiedzieć, że jest to "zapach kodu", ponieważ maksimum mogło zostać znalezione podczas generowania listy w pierwszej kolejności. Nie ma wystarczająco dużo miejsca, aby dowiedzieć się, dlaczego w tej niewielkiej przestrzeni wydaje się źle, może zaktualizuję odpowiedź później. – Phil

Odpowiedz

34

Jednym ze sposobów, aby to zrobić jest zip listy z jej indeksów, znalezienie otrzymanej pary z największą pierwszego elementu i powrócić do drugiego elementu, który para:

scala> List(0, 43, 1, 34, 10).zipWithIndex.maxBy(_._1)._2 
res0: Int = 1 

To nie jest najskuteczniejszy sposób rozwiązania problemu, ale jest idiomatyczny i jasny.

+0

Cholera, dokładnie to co chciałem powiedzieć ... Dodałem skrzynkę 'x.zipWithIndex.maxBy {case (i, v) => v} ._ 2' –

1

nawet łatwiejsze do odczytania byłoby:

val g = List(0, 43, 1, 34, 10) 
    val g_index=g.indexOf(g.max) 
0

Pimp my biblioteka! :)

class AwesomeList(list: List[Int]) { 
    def getMaxIndex: Int = { 
    val max = list.max 
    list.indexOf(max) 
    } 
} 

implicit def makeAwesomeList(xs: List[Int]) = new AwesomeList(xs) 
               //> makeAwesomeList: (xs: List[Int])scalaconsole.scratchie1.AwesomeList 

//Now we can do this: 
List(4,2,7,1,5,6) getMaxIndex    //> res0: Int = 2 

//And also this: 
val myList = List(4,2,7,1,5,6)   //> myList : List[Int] = List(4, 2, 7, 1, 5, 6) 
myList getMaxIndex      //> res1: Int = 2 

//Regular list methods also work 
myList filter (_%2==0)     //> res2: List[Int] = List(4, 2, 6) 

Więcej szczegółów na temat tego wzoru tutaj: http://www.artima.com/weblogs/viewpost.jsp?thread=179766

+0

Podczas gdy łatwo jest pisać, czyż nie? przeglądać listę dwa razy? –

+0

Tak, masz rację. Mam sposób na uzyskanie maksimum w jednej iteracji poprzez listę, ale myślę, że czytelność ma na to wielki wpływ. Ponadto wymaga użycia myList (index), aby pobrać konkretny element i nie jestem pewien, czy jest to efektywne. –

1
def maxIndex[ T <% Ordered[T] ] (list : List[T]) : Option[Int] = list match { 
    case Nil => None 
    case head::tail => Some(
     tail.foldLeft((0, head, 0)){ 
      case ((indexOfMaximum, maximum, index), elem) => 
       if(elem > maximum) (index, elem, index + 1) 
       else (indexOfMaximum, maximum, index + 1) 
     }._1 
    ) 
    } //> maxIndex: [T](list: List[T])(implicit evidence$2: T => Ordered[T])Option[Int] 


    maxIndex(Nil)       //> res0: Option[Int] = None 
    maxIndex(List(1,2,3,4,3))    //> res1: Option[Int] = Some(3) 
    maxIndex(List("a","x","c","d","e"))  //> res2: Option[Int] = Some(1) 

    maxIndex(Nil).getOrElse(-1)    //> res3: Int = -1 
    maxIndex(List(1,2,3,4,3)).getOrElse(-1) //> res4: Int = 3 
    maxIndex(List(1,2,2,1)).getOrElse(-1) //> res5: Int = 1 

W przypadku istnieje wiele maksima, zwraca pierwszy za indeks.

Plusy: Możesz używać tego z wieloma typami, lista jest wyświetlana tylko raz, możesz podać indeks domyślny zamiast wyjątku dla pustych list.

Minusy: Może wolisz wyjątki :) Nie jeden liniowiec.

+0

Cześć, gdzie mogę przeczytać o znaczeniu operatorów <% i <:, jest dość trudno wyszukiwać w Google (lub w dowolnym miejscu) dla operatorów, którzy nie są słowami. Ponadto, myślę, że mógłbyś użyć tailrec w swojej odpowiedzi ([przykład] (https://gist.github.com/trylks/6164315)). Dziękuję Ci. – Trylks

+0

[Znaleziono!] (Http://ofps.oreilly.com/titles/9780596155957/ScalasTypeSystem.html) Przepraszamy za pytanie. – Trylks

4

Od Seq jest funkcją w Scala, następujący kod działa:

list.indices.maxBy(list) 
Powiązane problemy