I'm trying to create a trait
for sorting functions like this:
trait Sorting:
def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C
and here is the implementation:
object InsertionSorting extends Sorting:
override def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C =
list.iterator
.foldLeft(ListBuffer.empty[A]) { (acc, x) =>
{
val index = acc.view.takeWhile(y => ord.lt(y, x)).size
acc.insert(index, x)
acc
}
}
.to(factory)
With a test:
class InsertionSortingSpec extends AnyFlatSpec with should.Matchers:
"A Sorting" should "sort correctly" in {
val sorting: Sorting = InsertionSorting
val input = Seq(31, 41, 59, 26, 41, 58)
val actual = sorting.sort(input)
actual shouldBe sorted
}
It works, so far so good.
But when I'm trying to replace the input in the test with an Array
class InsertionSortingSpec extends AnyFlatSpec with should.Matchers:
"A Sorting" should "sort correctly" in {
val sorting: Sorting = InsertionSorting
val input = Array(31, 41, 59, 26, 41, 58)
val actual = sorting.sort(input)
actual shouldBe sorted
}
Compile failed:
[error] 11 | val actual = sorting.sort(input)
[error] | ^
[error] |no implicit argument of type collection.Factory[A, scala.collection.mutable.ArraySeq.ofInt] was found for parameter factory of method sort in trait Sorting
[error] |
[error] |where: A is a type variable with constraint >: Int
So I had to add another method for Array in Sorting
:
trait Sorting:
def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C
def sort[A: ClassTag, B >: A](array: Array[A])(using Ordering[B]): Array[A] =
sort(array.iterator).toArray[A]
It works again. I know.
I just wondering is there any way that we can do it in one method?
BTW, the to
method for IterableOnce
, why the parameter factory
is not implicit?
def to[C1](/*using*/ factory: Factory[A, C1]): C1
CodePudding user response:
How about this:
Welcome to Scala 3.1.3-RC3 (17.0.3.1, Java Java HotSpot(TM) 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> import scala.reflect.ClassTag
scala> import scala.collection.mutable.ListBuffer
scala> import scala.collection.Factory
scala> object InsertionSorting:
| def sort[C, A](list: C)(using view: C => IterableOnce[A], tag: ClassTag[A], factory: Factory[A, C], ord: Ordering[A]): C =
| view(list).iterator
| .foldLeft(ListBuffer.empty[A]) { (acc, x) =>
| {
| val index = acc.view.takeWhile(y => ord.lt(y, x)).size
| acc.insert(index, x)
| acc
| }
| }
| .to(factory)
|
// defined object InsertionSorting
scala> InsertionSorting.sort(Array(3, 4, 5, 9, 1, 2))
val res0: Array[Int] = Array(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort(List(3, 4, 5, 9, 1, 2))
val res1: List[Int] = List(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort(Seq(3, 4, 5, 9, 1, 2))
val res2: Seq[Int] = List(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort("abcABC123")
val res3: String = 123ABCabc