Reputation: 2811
I have case class that represents report, and report have expenses.
case class FakeExpense(amount: Option[Double], country: Option[String], currency: Option[String])
case class FakeReport(id: Int, expenses: List[FakeExpense])
and I want to return true/false if report is valid or not, and it is not valid if there is 2 expenses with the exact same fields...what would be the right way with scala to do something like this?
a valid report:
val report = FakeReport(1, List(FakeExpense(Some(150), Some("US"), Some("USD")),FakeExpense(Some(85), Some("DE"), Some("EUR"))))
a non valid report:
val report = FakeReport(2, List(FakeExpense(Some(150), Some("US"), Some("USD")),FakeExpense(Some(150), Some("US"), Some("USD"))))
Thanks!
Upvotes: 2
Views: 75
Reputation: 48420
Consider List.distinct
approach like so
def isValidReport(report: FakeReport): Boolean =
report.expenses.distinct.length == report.expenses.length
The above solution makes three passes through the list. Applying Luis' comment we can reduce to two passes like so
def isValidReport(report: FakeReport): Boolean = {
report.expenses.sizeIs == report.expenses.iterator.distinct.length
}
We shave off one pass because distinct.length
collapses to a single transformation in iterator.distinct.length
. sizeIs
is a potential quick-savings where we might not have to go through the whole list.
Here is a single-pass tail-recursive solution based on HashSet
having O(eC) lookup and insertion
def isValidReport(report: FakeReport): Boolean = {
val set = mutable.HashSet[FakeExpense]()
@tailrec def loop(l: List[FakeExpense]): Boolean = l match {
case Nil => true
case h :: t => if (set.add(h)) loop(t) else false
}
loop(report.expenses)
}
Also note how we might return early on first duplicate.
Upvotes: 4
Reputation: 962
If you need exactly same reports disregarding double comparison with epsilon(|a-b| < epsilon, where epsilon is small enough), you just can turn list to set as it will remove duplicate entries and then check if the size of your list changed.
fakeReport.expenses.toSet.length == fakeReport.expenses.length
It will work till everything that inside your classes you want to use with == correctly implement equals methods (primitive types, most of default classes, case classes and objects do so). What will not implement this correctly is an array and possibly certain java classes and these classes wrapped into AnyVal classes.
Upvotes: 3