J'essayais d'écrire une fonction de test/timing pour les réponses fournies dans this SO question. Certaines réponses fonctionnent sur Array[T]
, certaines sur List[T]
, une sur Iterable[T]
et une sur String
! Ce que je voudrais écrire est une fonction qui prend les fonctions shift*
de la question ou les réponses, une liste d'entrée, un prédicat et une sortie attendue et exécuter la fonction. Un peu comme:Fonction travaillant sur les fonctions de Array [T] ou List [T] ou Iterable [T]
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
}
Sauf que je peux comprendre la signature, comme Array
semble avoir des propriétés mutables Seq
, alors que List
semble avoir Seq
immuables propriétés.
Quelle est la meilleure façon de gérer cela?
Modifier: En utilisant la suggestion de Thomas c'est à quel point je peux obtenir (fonctionne sur Array[Char]
, List[T]
mais pas sur 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]
Je marquerai la réponse de Daniel acceptée telle qu'elle compile et fournit moi une manière différente de réaliser ce que je voulais - à moins que la méthode sur Array [T] crée un nouveau tableau (et apporte des problèmes Manifest).
(2): How would be a functional approach to shifting certain array elements?
Tout d'abord, merci de concrétiser ce que je suggère dans la question, et de suggérer A et CC comme des types non liés liés par func. Le seul problème que j'ai rencontré est que la solution Array sur place ne correspond pas bien à l'exécution de la fonction plusieurs fois, car la sortie devient l'entrée de la prochaine fois. J'ai essayé de créer une nouvelle copie de tableau dans la fonction de décalage, mais j'ai ensuite rencontré un problème avec Manifest: 'Impossible de trouver une valeur implicite pour le paramètre evidence du type Manifest [T]'. – huynhjl
@huynhjl Oui, travailler avec des tableaux sur Scala 2.8 peut être difficile. Je pensais que vous auriez probablement à rendre la fonction curry, en passant dans la première liste de paramètres un 'Manifest [T]' explicite, et ensuite passer ce paramètre si nécessaire. Et, quand vous appelez 'test', passez le' Manifest' explicite pour cela aussi. Faites une autre question, et j'examinerai ceci. –