2010-05-21 18 views
9

Czy istnieje lepszy sposób to zrobić:Najlepszy sposób na zdobywanie punktów i sumy w Scali?

val totalScore = set.foldLeft(0)(_ + score(_)) 

lub to:

val totalScore = set.toSeq.map(score(_)).sum 

Myślę, że to dość powszechne działanie więc spodziewałem się czegoś bardziej elegancka jak:

val totalScore = set.sum(score(_)) 
+1

Pierwsze dwa fragmenty kodu robią różne rzeczy. Zobacz mój komentarz do odpowiedzi Daniela C. Sobrala. – dsg

+0

Dzięki @dsg, zmieniłem to. – adam77

Odpowiedz

17

Cóż, istnieją alternatywne sposoby, aby ją napisać:

val totalScore = set.toSeq.map(score(_)).sum 
val totalScore = set.toSeq.map(score).sum 
val totalScore = set.toSeq map score sum 

Ten ostatni może wymagać średnik na końcu jeśli następna linia nie zaczyna się od słowa kluczowego. Można również użyć .view zamiast .toSeq, co pozwoli uniknąć przydzielania kolekcji tymczasowej. Jednak nie jestem pewien, czy obecne zachowanie (pokazujące powtarzające się elementy) jest poprawne.

+1

To wydaje się być najprostszym i najbardziej odpowiednim rozwiązaniem. Wolałbym to przeczytać zamiast funkcji, która obejmuje wykonywanie mapowania. – ziggystar

+3

Uzasadnioną obawą w przypadku podejścia dwuetapowego może być wydajność - tworzy ona drugą listę, aby ją zsumować. Można jednak użyć widoku, aby uniknąć tego obciążenia: 'set.view.map (score) .sum'. Oddzielenie problemów związanych z mapowaniem i podsumowaniem pozwala uniknąć wydmuchiwania metod w standardowej bibliotece. Jeśli robisz to często, możesz dodać 'mapAndSum' do własnego kodu. – retronym

+0

Czy ktoś ma link do niektórych dokumentacji poglądów? – adam77

1

prostsza :

scala> val is1 = Set(1, 4, 9, 16) 
is1: scala.collection.immutable.Set[Int] = Set(1, 4, 9, 16) 
scala> is1.reduceLeft(_ + _) 
res0: Int = 30 

Dzięki swojej metodzie punktowej:

scoreSet.reduceLeft(_ + score(_)) 

Ostrzeżenie, choć to się nie powiedzie się, że kolekcja jest zmniejszona jest pusta podczas krotnie nie:

scala> val is0 = Set[Int]() 
is0: scala.collection.immutable.Set[Int] = Set() 

scala> is0.foldLeft(0)(_ + _) 
res1: Int = 0 
+3

To nie zadziała. Typ kolekcji różni się od typu wyniku (który jest powodem wywołania 'score'), więc' reduceLeft' nie jest opcją. –

1

przemian przeciążenie Seq#sum że trwa niejawna konwersja do Numeric może być użyty, jeśli typ w zbiorze, który ma być oceniany/sumowany, sam nie ma operatora dodawania. Jednak ponieważ jest to niejawny parametr konwersji, nie zostanie zastosowany, chyba że jest wymagany do wykonania kontroli typu ograniczenia zamknięcia.

5

Seq.sum nie przyjmuje funkcji, która mogłaby zostać wykorzystana do oceny sumy. Można zdefiniować niejawna konwersja który „alfonsów” Traversable:

implicit def traversableWithSum[A](t: Traversable[A])(implicit m: Numeric[A]) = new { 
    def sumWith(f: A => A) = t.foldLeft(m.zero)((a, b) => m.plus(a, f(b))) 
} 

def score(i: Int) = i + 1 

val s = Set(1, 2, 3) 

val totalScore = s.sumWith(score _) 
println(totalScore) 
=> 9 

Należy pamiętać, że cecha Numeric istnieje tylko w Scala 2.8.

+2

Michel, podoba mi się twoje rozwiązanie i pomyślałem, że sprawię, że stanie się on nieco bardziej ogólny, pozwalając, aby partytura działała na obiekcie, na przykład "Gra" i zwracała wartość liczbową: niejawna def traversableWithSum [A] (t: Traversable [A]) = nowy { defsumWith [B] (f: A => B) (niejawny m: Numeryczny [B]): B = t.kolityLek (m.zero) ((a, b) => m .plus (a, f (b))) } – Eric

Powiązane problemy