作用于 Array[T] 或 List[T] 或 Iterable[T] 函数的函数

发布于 2024-08-22 02:46:20 字数 3296 浏览 2 评论 0原文

我试图为 这个问题。有些答案适用于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 似乎具有不可变的 Seq 属性。

处理这个问题的最佳方法是什么?

编辑:使用托马斯的建议,这就是我可以获得的接近程度(适用于Array[Char]List[T],但不适用于< code>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]

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

(2): 如何是一种移动某些数组元素的函数方法吗?

I was trying to write a testing/timing function for answers provided in this SO question. Some answers work on Array[T], some on List[T], one on Iterable[T] and one on String!

What I'd like to write is a function that takes the shift* functions from the question or the answers, an input list, a predicate and an expected output and run the function. Sort of like:

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 I can figure out the signature, as Array seems to have mutable Seq properties, while List seems to have immutable Seq properties.

What's the best way to handle that?

Edit: Using Thomas' suggestion this is how close 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 mark Daniel's answer as accepted as it compiles and provides me a different way to achieve what I wanted - unless the method on Array[T] creates a new array (and brings in Manifest issues).

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不即不离 2024-08-29 02:46:20

一种方法是定义函数:

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

One way is to define the 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'))
夜无邪 2024-08-29 02:46:20

我会在 Scala 2.8 上使用 scala.collection.Seq ,因为此类型是所有有序集合的父类型。不幸的是,ArrayString 除外。人们可以通过视图边界来解决这个问题,如下所示:

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 上的 Array 版本,因为这需要 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))
}

这将像 find 一样工作。只要类型匹配,该程序就不需要了解 CC 是什么。

I'd use scala.collection.Seq on Scala 2.8, as this type is parent to all ordered collections. Except Array and String, unfortunately. One can get around that with view bounds, like this:

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'm currying this function so that the input (and expected) can be used to infer the type. Anyway, this won't work with your own Array version on Scala 2.8, because that requires a Manifest. I'm sure it can be provided here somehow, but I don't see quite how.

But say you ignore all that stuff about sequences, arrays, etc. Just remove the view bound from the function, and you get this:

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

Which will work just as find. As long the type match, it isn't really relevant for this program to know what a CC is.

暖心男生 2024-08-29 02:46:20

您提到的所有类型(甚至 String)都是显式(List)或隐式(Array 和 String)Iterable,因此您所要做的就是在您现在使用 Seq 的方法签名中使用 Iterable。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文