2016-07-15 14 views
1

Ich glaube, es muss eine bessere Möglichkeit, diese Frage zu stellen, aber ich konnte nicht daran denken.Holen Sie sich den neuesten Standort vieler Benutzer

Betrachten Sie diese Fallklasse:

case class UserLocation(id: Int, dateTime: DateTime, lat: Double, lon: Double) 

ich eine List[UserLocation] mit der Geschichte aller Standorte aller Nutzer haben, und ich möchte diese Liste filtern, um nur die letzte Stelle von jedem von ihnen haben.

Hier ist, wie ich es tat:

implicit def dateTimeOrdering: Ordering[DateTime] = Ordering.fromLessThan(_ isAfter _) 

val locations: List[UserLocation] = bigListOfUserLocations() 
val groupedById = locations.groupBy(_.id) 
val sortedByDate = groupedById.map(_._2.sortBy(_.dateTime)) 
val finalList = sortedByDate.map(_.head) 

Dies funktioniert, aber was ich möchte, ist wissen, ob es ein besserer Weg, dies zu tun, die Leistung zu verbessern und/oder Lesbarkeit

WICHTIG: Dies ist meist eine akademische Frage, würde ich gerne die performatic oder idiomatische Art und Weise erreichen dies auf manipulierenden Listen, so Vorschläge wie "versuchen xyz auf der Datenbank, bevor Sie die Liste" wird nicht sein hilfreich

Antwort

2

Sie sind im Grunde gibt, aber Sie können die letzten beiden Operationen ein mit reduzieren:

val finalList = groupedById.map(_._2.maxBy(_.dateTime)) 

Dies ist besser lesbar und performanter, da Sie nur das größte Element in der Gruppe finden wihtout zu müssen den Rest in Ordnung bringen.

+0

Oh, sehr interessant. Ich war mir dieser MaxBy-Methode nicht bewusst. Vielen Dank –

+1

Seien Sie vorsichtig, da 'maxBy' eine Teilfunktion ist -' scala> Liste [(Int, Int)](). MaxBy (_._ 1) java.lang.UnsupportedOperationException: empty.maxBy' –

0

Wie bereits von @Iadams erwähnt, muss hier nicht sortiert werden. Meine Lösung nicht verbessert die Lesbarkeit, sondern verbessert die Leistung ein wenig (obwohl es noch O(n) ist), da sie nicht alle für einen Benutzer die Standorte nicht speichern, aber die jüngsten, in einem Durchlauf durch die Liste:

locations 
    .foldLeft(mutable.Map.empty[Int, UserLocation]) { 
     case (acc, loc) 
     if !acc.contains(loc.id) || 
      acc(loc.id).dateTime < loc.dateTime => acc.updated(loc.id, loc) 
     case (acc, _) => acc 
    }.map(_._2) 
Verwandte Themen