Scala - вычислить среднее значение SomeObj.double в списке [SomeObj] - PullRequest
11 голосов
/ 17 августа 2010

У меня второй вечер scala, и я сопротивляюсь желанию писать вещи в scala, как я делал это в java и пытаюсь выучить все идиомы. В этом случае я просто рассчитываю среднее значение, используя такие вещи, как замыкания, отображение и, возможно, понимание списка. Независимо от того, является ли это наилучшим способом вычисления среднего значения, я просто хочу знать, как делать эти вещи в Scala только для учебных целей

Вот пример: усредненный метод, приведенный ниже, практически не реализован. У меня есть пара других методов для поиска рейтинга, который дал отдельный идентификатор пользователя, который использует метод find из TraversableLike (я думаю), но на самом деле ничего более специфичного для scala. Как бы я вычислил среднее значение для заданного List [RatingEvent], где RatingEvent.rating - это двойное значение, которое я бы вычислял в среднем по всем значениям этого Списка в форме, подобной скале?.

package com.brinksys.liftnex.model

class Movie(val id : Int, val ratingEvents : List[RatingEvent]) {

    def getRatingByUser(userId : Int) : Int =  {
        return getRatingEventByUserId(userId).rating
    }

    def getRatingEventByUserId(userId : Int) : RatingEvent = {
        var result = ratingEvents find {e => e.userId == userId }
        return result.get
    }

    def average() : Double = {
        /* 
         fill in the blanks where an average of all ratingEvent.rating values is expected
        */
       return 3.8
    }
}

Как опытный специалист по scala может заполнить этот метод и использовать возможности scala, чтобы сделать его максимально кратким? Я знаю, как бы это сделать в Java, чего я хочу избежать.

Если бы я делал это на python, я предполагаю, что самый питонический способ был бы:

sum([re.rating. for re in ratingEvents]) / len(ratingEvents)

или если бы я заставлял себя использовать замыкание (что я, по крайней мере, хочу изучить в scala):

reduce(lambda x, y : x + y, [re.rating for re in ratingEvents]) / len(ratingEvents)

Это использование таких вещей, которым я хочу научиться в Scala.

Ваши предложения? Любые указатели на хорошие учебники / справочные материалы, относящиеся к этому, приветствуются: D

Ответы [ 4 ]

30 голосов
/ 17 августа 2010

Если вы собираетесь заниматься математикой, использование List не всегда является самым быстрым способом, потому что List не знает, как долго это происходит, поэтому ratingEvents.length требует времени, пропорционального длине , (Не очень много времени предоставлено, но оно должно пройти через весь список, чтобы сказать.) Но если вы в основном манипулируете структурами данных и только изредка нуждаетесь в вычислении суммы или чего-то еще, так критическое по времени ядро ​​вашего кода, тогда использование List - это модно.

В любом случае, каноническим способом сделать это было бы сложение для вычисления суммы:

(0.0 /: ratingEvents){_ + _.rating} / ratingEvents.length

// Equivalently, though more verbosely:
// ratingEvents.foldLeft(0.0)(_ + _.rating) / ratingEvents.length

или путем отображения, а затем суммирования (только 2,8):

ratingEvents.map(_.rating).sum / ratingEvents.length

Для получения дополнительной информации о картах и ​​сгибах см. этот вопрос по этой теме .

10 голосов
/ 17 августа 2010

Вы могли бы вычислить сумму и длину за один раз, но я сомневаюсь, что это помогает, за исключением очень длинных списков. Это будет выглядеть так:

val (s,l) = ratingEvents.foldLeft((0.0, 0))((t, r)=>(t._1 + r.rating, t._2 + 1)) 
val avg = s / l

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

4 голосов
/ 10 декабря 2015

Поскольку mean и другие описательные статистические данные, такие как standard deviation или median, необходимы в различных контекстах, вы также можете использовать небольшой неявный многократно используемый вспомогательный класс, чтобы учесть более упорядоченные объединенные команды:1006 * Даже представляется возможным написать это в общем виде для всех типов чисел.

1 голос
/ 13 января 2017

Я могу предложить 2 способа:

def average(x: Array[Double]): Double = x.foldLeft(0.0)(_ + _) / x.length

def average(x: Array[Double]): Double = x.sum / x.length

Оба в порядке, но в 1 случае при использовании сгиба вы можете не только выполнить операцию «+», но и заменить ее на другую (- или *например)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...