代码之家  ›  专栏  ›  技术社区  ›  huynhjl bhericher

函数处理数组[t]或列表[t]或可Iterable[t]的函数

  •  4
  • huynhjl bhericher  · 技术社区  · 14 年前

    我正试图为中提供的答案编写一个测试/计时函数。 this SO question . 一些答案是有效的 Array[T] 一些 List[T] 之一 Iterable[T] 还有一个 String !

    我想写的是一个函数 shift* 函数来自问题或答案、输入列表、谓词和预期输出,并运行函数。有点像:

    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
    }
    

    除非我能找出签名 Array 似乎有可变的 Seq 属性,而 List 似乎有不变的 顺序 性质。

    最好的方法是什么?

    编辑 :根据托马斯的建议,这是我能接近的距离 Array[Char] , 表[t] 但不是 数组[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]
    

    我会将Daniel的答案标记为在编译时被接受,并提供一种不同的方法来实现我想要的结果,除非数组[T]上的方法创建了一个新的数组(并引入了清单问题)。

    (二): How would be a functional approach to shifting certain array elements?

    3 回复  |  直到 14 年前
        1
  •  1
  •   Daniel C. Sobral    14 年前

    我会用 scala.collection.Seq 在scala 2.8上,因为此类型是所有已排序集合的父级。除了 Array String ,不幸的是。我们可以用视图边界来绕过它,如下所示:

    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))
    }
    

    我正在使用此函数,以便可以使用输入(和预期的)来推断类型。不管怎样,这不适合你自己 数组 scala 2.8上的版本,因为这需要 Manifest . 我肯定可以在这里提供,但我不太明白。

    但是假设您忽略了所有关于序列、数组等的内容,只需从函数中移除视图绑定,就可以得到:

    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))
    }
    

    这和发现一样有效。只要类型匹配,知道什么是 CC 是。

        2
  •  3
  •   Thomas Jung    14 年前

    一种方法是定义函数:

    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
  •  1
  •   Randall Schulz    14 年前

    您提到的所有类型(甚至是字符串)都是显式(list)或隐式(array和string)可Iterable,所以您所要做的就是在方法签名中使用Iterable,现在在方法签名中使用seq。