Can someone give me advise about how to eliminate the need for the 3rd argument, less
, in the following function. Is it really necessary? The function does a “join” of two iterables of tuples, a tuple of (K,V1)
and a tuple of (K,V2)
. The speed comes from the fact that I require type K
to be Orderable, and I require the caller to give me the less-than function to use.
Isn’t there some way syntactically to demand that K
is itself is an ordered structure, and just use the k1 < k2
syntax, letting the compiler figure out how to compare the elements?
In practice, I always call the function with K
being (String,String)
, and my less function compares the first elements unless they are ==
in which case it compares the second elements. However, any well defined order would suffice for my function to work.
def join[K,V1,V2](seq1:Iterable[(K,V1)],
seq2:Iterable[(K,V2)],
less:(K,K)=>Boolean):Iterable[(K,(V1,V2))] = {
val sorted1 = seq1.toList.sortWith{(a,b) => less(a._1,b._1)}
val sorted2 = seq2.toList.sortWith{(a,b) => less(a._1,b._1)}
def joinTail(
s1:List[(K,V1)],
s2:List[(K,V2)],
joined:List[(K,(V1,V2))]):List[(K,(V1,V2))] = {
(s1,s2) match {
case (Nil,_) => joined
case (_,Nil) => joined
case ((k1,v1)::t1, (k2,v2)::t2) => {
def common[V](e:(K,V)):Boolean = {
e._1 == k1
}
if (k1 == k2) {
val (prefix1, suffix1) = s1.span(common)
val (prefix2, suffix2) = s2.span(common)
val prefix3 = for {
x <- prefix1;
y <- prefix2
} yield (k1, (x._2, y._2))
joinTail(suffix1, suffix2, prefix3 ++ joined)
}
else if (less(k1, k2)) // k1 < k2
joinTail(t1, s2, joined)
else //if ( k2 < k1)
joinTail(s1, t2, joined)
}
}
}
joinTail(sorted1,sorted2,List())
}