8
votes

Sélection trier dans Scala fonctionnel

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?

http://gist.github.com/225870


6 commentaires

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 .


11 Réponses :


0
votes

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.

Cela commencerait à se débarrasser de certains Vars.

C'était probablement la leçon la plus difficile pour moi, essayant de vous déplacer davantage vers la FP.

J'hésite à montrer des solutions ici, car je pense qu'il serait préférable que vous essayiez d'abord.

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


1 commentaires

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.



1
votes

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é.


1 commentaires

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.



12
votes

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


3 commentaires

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!



2
votes

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.

Le problème principal que vous ferez face est que vous ne pouvez pas échanger des éléments . Voici pourquoi cela est important. Supposons avoir une liste (A 0 A X A N ), où un X est la valeur minimale. Vous devez obtenir un x , puis composez une liste (A 0 A X-1 A X + X + 1 a n ). Le problème est que vous devez nécessairement copier les éléments A 0 à un x-1 , 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.


1 commentaires

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.



1
votes

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> xxx pré>

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.


0 commentaires

1
votes

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


0 commentaires

2
votes

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


0 commentaires

0
votes

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


0 commentaires

1
votes

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> xxx pré>

Comme vous pouvez le constater, pour atteindre le polymorphisme paramétrique, plutôt que d'utiliser 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>

Vous pouvez écrire un programme client comme suit: 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))


0 commentaires

1
votes

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


0 commentaires

0
votes

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


0 commentaires