Reputation: 91
Hello I have this exercise where I am trying to find all numbers that do not exist in the second element of a tuple, and print them out in a list. I have a working version but it returns duplicate values, and it is not being returned in a list. I cant seem to use distinct here. Can any one explain to me why distinct cannot be used here and what i would need to do instead. Also if there is a better way to get the answer to the exercise, that would be appreciated.
object Example{
def main(args: Array[String]): Unit = {
val tupleExercise: List[(Int,Int)] = List(
(1, 3),
(2, 3),
(3, 6),
(5, 6),
(5, 7),
(4, 5),
(4, 8),
(4, 9),
(9, 11)
)
def notExistsInSecond(n: List[(Int, Int)]): Unit = {
var potential =
for (a <- n) {
for (c <- n)
if(c._1 == a._2) println(a._1)
}
}
println(notExistsInSecond(tupleExercise))
}
}
//expected ouput
// [1, 2, 4]
Upvotes: 0
Views: 364
Reputation: 27383
I don't think there is a (performant) way to write it in one line, but you could write it like this:
def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
val second = n.map(_._2).distinct
n.map(_._1).distinct.filterNot(second.contains)
}
It gets probabely more performant if you use a HashSet
instead of a List
for the lookup:
def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
val valuesSet = n.map(_._2).toSet
n.map(_._1).distinct.filterNot(valuesSet.contains)
}
Upvotes: 3
Reputation: 22895
The same logic as Raphael but more performant.
def notExistsInSecond[A](n: List[(A, A)]): List[A] = {
val seconds = n.iterator.map(_._2).toSet
val (result, _) = n.foldLeft(List.empty[Int] -> Set.empty[Int]) {
case ((result, added), (e, _)) =>
if (!seconds(e) && !added(e))
(e :: result) -> (added + e)
else
result -> added
}
result.reverse // If you do not care about the order you can remove this reverse
}
Or if you do not care about the result being a list, this would be even faster:
def notExistsInSecond[A](n: List[(A, A)]): Set[A] = {
val seconds = n.iterator.map(_._2).toSet
n.iterator.collect {
case (e, _) if (!seconds(e)) => e
}.toSet
}
Upvotes: 1
Reputation: 51271
Here's a way to do it with a single pass through the input list and using Set
to insure distinct results.
def notExistsInSecond(n: List[(Int, Int)]): List[Int] = {
val (s1,s2) = n.foldLeft((Set.empty[Int],Set.empty[Int])){
case ((sa,sb),(a,b)) => (sa+a, sb+b)
}
(s1 diff s2).toList
}
Upvotes: 1