Created
July 29, 2015 08:26
-
-
Save diversit/1ceea1c8cf84a44ecbc8 to your computer and use it in GitHub Desktop.
Distinct elements of a List (or Seq) based on a property of the element
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Extends a List[A] with a 'distinctOn' method to be able to distinct the elements | |
* of a list based on an element property. | |
* | |
* For example: | |
* In a List of Subscription's, we only want to send a certain Subscription.subscriber | |
* a message once even though the subscriber has multiple subscriptions. | |
* {{{ | |
* subscriptions.distinctOn(_.subscriber) // returns List[Subscription] with unique subscribers | |
* }}} | |
* | |
* Another way to do this, is just to map the Subscription to subscribers and distinct on that list. | |
* This only works if you do not need any other property of the Subscription anymore. | |
* {{{ | |
* subscriptions.map(_.subscriber).distinct // returns List[Subscriber] !! | |
* }}} | |
*/ | |
implicit class DistinctFunctionSeq[A](val list: List[A]) extends AnyVal { | |
/** | |
* Returns a list of type A where all items whould be unique if | |
* function 'f' would be applied on each element on the list. | |
* | |
* This can be used to distinct a list based on a property of type A. | |
* For example, a list with persons where person.city is unique. | |
* | |
* Note that the resulting function contains the elements of the list in | |
* reversed order!! | |
* | |
* @param f Function to map element A into a B which is used to determine whether the element is unique. | |
* @tparam B Type of mapping of A | |
*/ | |
def distinctOn[B](f: A => B): List[A] = list.foldLeft(List.empty[A]) { (acc, elem) => | |
val value = f(elem) | |
// check if accumelator already contains an element with same value | |
acc.find(item => f(item) == value) match { | |
case Some(_) => acc // if found, do not add but return accumelation | |
case None => elem :: acc // if not found, add elem to accumelation | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment