Function working on array functions [T] or List [T] or Iterable [T]

I tried to write a test / synchronization function for the answers presented in this SO question . Some answers work on Array[T] , some on List[T] , one on Iterable[T] and one on String !

What I would like to write is a function that takes shift* functions from a question or answers, an input list, a predicate, and the expected output, and runs the function. Example:

 def test[T]( func:(Seq[T], T=>Boolean) => Seq[T], input:Seq[T], predicate:T=>Boolean, expected:Seq[T]): Unit = { // may be some warm up // ... time start, run func, time stop, // check output against expected } 

Except that I can define a signature, since Array seems to have mutable Seq properties, while List has immutable Seq properties.

What is the best way to handle this?

Change Using Thomas's suggestion, as far as I can get (works on Array[Char] , List[T] , but not on Array[T] ):

 val inputArr = Array('a', 'b', 'C', 'D') val expectArr = Array('a', 'C', 'D', 'b') val inputList = inputArr.toList val expectList = expectArr.toList def test[I, T]( func:(I, T=>Boolean) => Traversable[T], input: I, predicate: T=>Boolean, expected: Traversable[T]): Boolean = { val result = func(input, predicate) if (result.size == expected.size) { result.toIterable.zip(expected.toIterable).forall(x => x._1 == x._2) } else { false } } // this method is from Geoff [there][2] def shiftElements[A](l: List[A], pred: A => Boolean): List[A] = { def aux(lx: List[A], accum: List[A]): List[A] = { lx match { case Nil => accum case a::b::xs if pred(b) && !pred(a) => aux(a::xs, b::accum) case x::xs => aux(xs, x::accum) } } aux(l, Nil).reverse } def shiftWithFor[T](a: Array[T], p: T => Boolean):Array[T] = { for (i <- 0 until a.length - 1; if !p(a(i)) && p(a(i+1))) { val tmp = a(i); a(i) = a(i+1); a(i+1) = tmp } a } def shiftWithFor2(a: Array[Char], p: Char => Boolean):Array[Char] = { for (i <- 0 until a.length - 1; if !p(a(i)) && p(a(i+1))) { val tmp = a(i); a(i) = a(i+1); a(i+1) = tmp } a } def shiftMe_?(c:Char): Boolean = c.isUpper println(test(shiftElements[Char], inputList, shiftMe_?, expectList)) println(test(shiftWithFor2, inputArr, shiftMe_?, expectArr)) //following line does not compile println(test(shiftWithFor, inputArr, shiftMe_?, expectArr)) //found : [T](Array[T], (T) => Boolean) => Array[T] //required: (?, (?) => Boolean) => Traversable[?] //following line does not compile println(test(shiftWithFor[Char], inputArr, shiftMe_?, expectArr)) //found : => (Array[Char], (Char) => Boolean) => Array[Char] //required: (?, (?) => Boolean) => Traversable[?] //following line does not compile println(test[Array[Char], Char](shiftWithFor[Char], inputArr, shiftMe_?, expectArr)) //found : => (Array[Char], (Char) => Boolean) => Array[Char] //required: (Array[Char], (Char) => Boolean) => Traversable[Char] 

I will answer Daniel's question as accepted, how he compiles, and will provide me with another way to achieve what I wanted - if the Array [T] method does not create a new array (and leads to manifest problems).

(2): How will the functional approach to moving certain elements of the array?

+4
source share
3 answers

I would use scala.collection.Seq in Scala 2.8, since this type is the parent of all ordered collections. Unfortunately, apart from Array and String . You can get around this with view restrictions, for example:

 def test [A, CC <% scala.collection.Seq[A]] (input: CC, expected: CC) (func: (CC, A => Boolean) => CC, predicate: A => Boolean): Unit = { def times(n: Int)(f: => Unit) = 1 to n foreach { count => f } def testFunction = assert(func(input, predicate) == expected) def warm = times(50) { testFunction } def test = times(50) { testFunction } warm val start = System.currentTimeMillis() test val end = System.currentTimeMillis() println("Total time "+(end - start)) } 

I perform this function so that the input (and expected) can be used to type inference. In any case, this will not work with your own version of Array on Scala 2.8, because it requires Manifest . I am sure that it can be presented here somehow, but I do not understand how to do it.

But say that you ignore all these things about sequences, arrays, etc. Just remove the view constraint from the function and you will get the following:

 def test [A, CC] (input: CC, expected: CC) (func: (CC, A => Boolean) => CC, predicate: A => Boolean): Unit = { def times(n: Int)(f: => Unit) = 1 to n foreach { count => f } def testFunction = assert(func(input, predicate) == expected) def warm = times(50) { testFunction } def test = times(50) { testFunction } warm val start = System.currentTimeMillis() test val end = System.currentTimeMillis() println("Total time "+(end - start)) } 

That will work the same as find. Once a type match, for this program it really does not matter what <<27> is.

+1
source

One way is to define a function:

 def test[I, T]( func:(I, T=>Boolean) => Traversable[T], input: I, predicate: T=>Boolean, expected: Traversable[T]): Unit = { println(func(input, predicate)) } def g(x : Char) = true test((x : String, y: Char => Boolean) => x, "asdf", g _ , "expected") test((x : List[Char], y: Char => Boolean) => x, List('s'), g _, List('e')) test((x : Array[Char], y: Char => Boolean) => x, Array('s'), g _, Array('e')) test((x : Iterable[Char], y: Char => Boolean) => x, Set('s'), g _, Set('e')) 
+3
source

All the types you mention (even String) are explicitly specified in the (List) element or implicitly (Array and String) Iterable, so all you have to do is use Iterable in your method signature, where you are now using Seq.

+1
source

Source: https://habr.com/ru/post/1301128/


All Articles