Je me sens à travers la "programmation à Scala" et j'ai écrit une mise en œuvre rapide de l'algorithme de sélection de sélection. Cependant, comme je suis toujours un peu green dans la programmation fonctionnelle, je rencontre des difficultés à traduire dans un style plus scala-ish. Pour les programmeurs Scala, comment puis-je faire cela à l'aide de listes et de vals plutôt que de revenir à mes manières impératives? P>
11 Réponses :
Vous voudrez peut-être essayer de remplacer votre tandis que des boucles avec récursivité, vous disposez donc de deux endroits où vous pouvez créer de nouvelles fonctions récursives. P>
Cela commencerait à se débarrasser de certains Vars. p>
C'était probablement la leçon la plus difficile pour moi, essayant de vous déplacer davantage vers la FP. P>
J'hésite à montrer des solutions ici, car je pense qu'il serait préférable que vous essayiez d'abord. P>
Mais, si possible, vous devriez utiliser la récursion de la queue, pour éviter les problèmes avec des débordements de pile (si vous triez une très très grande liste). P>
Oui, ce n'est pas tellement la récursion que la mise en œuvre littérale de la fonction récursive que je tombe court. J'ai également mis à jour le gist avec pseudo code aussi. Merci pour le conseil, cependant ... Je vais continuer à se brancher.
Vous avez besoin d'une fonction d'assistance qui fait la sélection. Il devrait renvoyer l'élément minimal et le reste de la liste avec l'élément supprimé. P>
C'est exactement la partie dont je suis un peu en difficulté avec ... je peux penser à des façons très inefficaces de faire cela, mais rien de tout cela ne semble idéal. J'ai également mis à jour le gist avec un pseudo-code aussi.
comme Starblue déjà dit , vous avez besoin d'une fonction qui calcule Le minimum d'une liste et renvoie la liste avec cet élément supprimé. Voici ma queue de mise en œuvre récursive de quelque chose de similaire (comme je pense que Foldl code> est récursive de la queue dans la bibliothèque standard), et j'ai essayé de le rendre aussi fonctionnel que possible :). Il renvoie une liste contenant tous les éléments de la liste d'origine (mais garantie de sens inverse - voir l'explication ci-dessous) avec le minimum comme une tête. maximum(25 12 64 22 11)
25 :: Nil /: 12 64 22 11 -- 25 > 12, so it stays as head
25 :: 12 /: 64 22 11 -- same as above
64 :: 25 12 /: 22 11 -- 25 < 64, so the new head is 64
64 :: 22 25 12 /: 11 -- and stays so
64 :: 11 22 25 12 /: Nil -- until the end
64 11 22 25 12
Je recommande de faire la fonction de la queue récursive une sous-fonction de la principale. Sinon, vous devez vous inquiéter de choses comme la classe ou la méthode finale pour que l'optimisation puisse être appliquée.
Oui, c'est une bonne idée, merci. Je modifierai ma réponse pour l'avoir comme une sous-fonction.
Cela est superficiellement utile non seulement dans ma question spécifique, mais aussi bien en favorisant ma compréhension du FP. Merci, flaviu!
Vous devriez avoir des problèmes de sélection dans le style fonctionnel, car il s'agit d'un algorithme de tri en place. En place, par définition, n'est pas fonctionnel. P>
Le problème principal que vous ferez face est que vous ne pouvez pas échanger des éléments em>. Voici pourquoi cela est important. Supposons avoir une liste (A 0 SUB> A X SUB> A N SUB>), où un X SUB > est la valeur minimale. Vous devez obtenir un x sub>, puis composez une liste (A 0 SUB> A X-1 SUB> A X + X + 1 sub> a n sub>). Le problème est que vous devez nécessairement copier em> les éléments A 0 sub> à un x-1 sub>, si vous souhaitez rester purement fonctionnel. D'autres structures de données fonctionnelles, en particulier des arbres, peuvent avoir une meilleure performance que cela, mais le problème de base reste. P>
Encore une version fonctionnelle de celui-ci, qui ne peut pas être mise en place comme vous l'avez souligné, est probablement précieuse à des fins éducatives / d'apprentissage.
Je pense que c'est raisonnablement possible de faire une sélection dans un style fonctionnel, mais comme Daniel l'indiquait, il a de bonnes chances d'accomplir horriblement.
Je viens de m'essayer de la main d'une bulle fonctionnelle, comme un peu Un cas de sélection plus simple et dégénéré. Voici ce que j'ai fait, et cela sugviennent à ce que vous pouviez faire: p> une fois que c'est fini recouvrant, le plus grand élément est à la fin de la liste. Maintenant, P> Break list into two sub-lists,
either by counting off half the elements into one sublist
and the rest in the other,
or by copying every other element from the original list
into either of the new lists.
Sort each of the two smaller lists (recursion here, obviously).
Assemble a new list by selecting the smaller from the front of either sub-list
until you've exhausted both sub-lists.
Merci pour les indices ci-dessus, ils étaient très inspirants. Voici une autre approche fonctionnelle de l'algorithme de tri de sélection. J'ai essayé de le baser sur l'idée suivante: la recherche d'un max / min peut être faite assez facilement par min (a) = si a = nil -> int.maxvalue d'autre min (A.Head, min (A.tail ))) code>. Le premier min est la min d'une liste, la seconde la minute de deux chiffres. Ceci est facile à comprendre, mais malheureusement pas à la queue récursive. Utilisation de la méthode de l'accumulateur La définition MIN peut être transformée comme ceci, maintenant dans la correction SCALA: def ssort(xs: List[Int], accu: List[Int]): List[Int] = minl(xs) match {
case Nil => accu
case min :: rest => ssort(rest, min::accu)
}
Voici une autre implémentation de la sélection de sélection (version générique).
def less[T <: Comparable[T]](i: T, j: T) = i.compareTo(j) < 0
def swap[T](xs: Array[T], i: Int, j: Int) { val tmp = xs(i); xs(i) = xs(j); xs(j) = tmp }
def selectiveSort[T <: Comparable[T]](xs: Array[T]) {
val n = xs.size
for (i <- 0 until n) {
val min = List.range(i + 1, n).foldLeft(i)((a, b) => if (less(xs(a), xs(b))) a else b)
swap(xs, i, min)
}
}
Voici mon point de vue sur ce problème: sélectionsort. SCALA
def selectionsort[A <% Ordered[A]](list: List[A]): List[A] = {
def sort(as: List[A], bs: List[A]): List[A] = as match {
case h :: t => select(h, t, Nil, bs)
case Nil => bs
}
def select(m: A, as: List[A], zs: List[A], bs: List[A]): List[A] =
as match {
case h :: t =>
if (m > h) select(m, t, h :: zs, bs)
else select(h, t, m :: zs, bs)
case Nil => sort(zs, m :: bs)
}
sort(list, Nil)
}
même si, lorsque vous préférez Scala, je préfère préférer le style de programmation fonctionnelle (via des combinaisons ou une récursivité) sur un style impératif (via des variables et des itérations), cette fois, pour ce problème spécifique, les boucles imbriquées de l'ancienne écolière entraînent Code plus simple et plus performant.
Je ne pense pas que la retouche au style impératif est une erreur de certains classes de problèmes, tels que le tri des algorithmes qui transforment généralement le tampon d'entrée en place plutôt que sur une nouvelle collection. p>
Ma solution est la suivante: p> Comme vous pouvez le constater, pour atteindre le polymorphisme paramétrique, plutôt que d'utiliser Vous pouvez écrire un programme client comme suit: P> java.lang.cablable code>, J'ai préféré scala.math.Ordered code> et Scala View limites plutôt que les limites supérieures. Cela fonctionne certainement grâce à des conversions implicites Scala implicites de types primitifs vers des wrappers riches. P> import bitspoke.algo._
import scala.collection.mutable._
val sorter = new SelectionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)
assert(sorter.sorted(buffer))
Un programme fonctionnel simple pour la sélection - Trier dans SCALA
def selectionSort(list:List[Int]):List[Int] = {
@tailrec
def selectSortHelper(list:List[Int], accumList:List[Int] = List[Int]()): List[Int] = {
list match {
case Nil => accumList
case _ => {
val min = list.min
val requiredList = list.filter(_ != min)
selectSortHelper(requiredList, accumList ::: List.fill(list.length - requiredList.length)(min))
}
}
}
selectSortHelper(list)
}
Voici ma solution
def sort(list: List[Int]): List[Int] = {
@tailrec
def pivotCompare(p: Int, l: List[Int], accList: List[Int] = List.empty): List[Int] = {
l match {
case Nil => p +: accList
case x :: xs if p < x => pivotCompare(p, xs, accList :+ x)
case x :: xs => pivotCompare(x, xs, accList :+ p)
}
}
@tailrec
def loop(list: List[Int], accList: List[Int] = List.empty): List[Int] = {
list match {
case x :: xs =>
pivotCompare(x, xs) match {
case Nil => accList
case h :: tail => loop(tail, accList :+ h)
}
case Nil => accList
}
}
loop(list)
}
Vous voudrez peut-être ajouter le code à votre question, car cela faciliterait les autres.
Notez l'URL référencée (GIST) dans la question pour un code exemple.
Si vous donnez un nom à la gist qui se termine par .scala, il mettra en évidence le code; qui aiderait à la lire.
Mon navigateur (c'est-à-dire 8) ne montrera même rien avec ce lien.
GIST.GITUB.COM/226158 Forked pour ajouter une surbrillance de la syntaxe
Il existe un site Stackexchange dédié pour évaluation de code .