作用于 Array[T] 或 List[T] 或 Iterable[T] 函数的函数
我试图为 这个问题。有些答案适用于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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
一种方法是定义函数:
One way is to define the function:
我会在 Scala 2.8 上使用 scala.collection.Seq ,因为此类型是所有有序集合的父类型。不幸的是,
Array
和String
除外。人们可以通过视图边界来解决这个问题,如下所示:我正在柯里化这个函数,以便输入(和预期)可以用于推断类型。无论如何,这不适用于您自己的 Scala 2.8 上的
Array
版本,因为这需要Manifest
。我确信可以以某种方式在这里提供它,但我不知道如何提供。但是假设您忽略了有关序列、数组等的所有内容。只需从函数中删除视图绑定,您就会得到以下结果:
这将像 find 一样工作。只要类型匹配,该程序就不需要了解
CC
是什么。I'd use
scala.collection.Seq
on Scala 2.8, as this type is parent to all ordered collections. ExceptArray
andString
, unfortunately. One can get around that with view bounds, like this: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 aManifest
. 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:
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.您提到的所有类型(甚至 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.