Quel est le rendement de Scala?

Je comprends le rendement de Ruby et de Python. Que fait le rendement de Scala?

289
demandé sur Peter Mortensen 2009-06-27 13:18:56

9 réponses

Il est utilisé dans sequence comprehensions (comme les list-comprehensions et les générateurs de Python, où vous pouvez également utiliser yield).

Il est appliqué en combinaison avec for et écrit un nouvel élément dans la séquence résultante.

Exemple Simple (à partir de Scala-lang )

/** Turn command line arguments to uppercase */
object Main {
  def main(args: Array[String]) {
    val res = for (a <- args) yield a.toUpperCase
    println("Arguments: " + res.toString)
  }
}

L'expression correspondante en F#, serait

[ for a in args -> a.toUpperCase ]

Ou

from a in args select a.toUpperCase 

Dans Linq.

Ruby yield a un effet différent.

193
répondu Dario 2009-06-27 09:59:10

Je pense que la réponse acceptée est grande, mais il semble que beaucoup de gens ont échoué à saisir certains points fondamentaux.

Tout D'abord, les compréhensions for de Scala sont équivalentes à la notation do de Haskell, et ce n'est rien de plus qu'un sucre syntaxique pour la composition de multiples opérations monadiques. Comme cette déclaration n'aidera probablement personne qui a besoin d'aide, essayons à nouveau...: -)

Les compréhensions de Scala for sont des sucres syntaxiques pour la composition de plusieurs opérations avec la carte, flatMap et filter. Ou foreach. Scala traduit en fait une expression for en appels à ces méthodes, de sorte que toute classe qui les fournit, ou un sous-ensemble d'entre eux, peut être utilisée pour les compréhensions.

Parlons D'abord des traductions. Il y a des règles très simples:

  1. Ce

    for(x <- c1; y <- c2; z <-c3) {...}
    

    Est traduit en

    c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
    
  2. Ce

    for(x <- c1; y <- c2; z <- c3) yield {...}
    

    Est traduit en

    c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
    
  3. Ce

    for(x <- c; if cond) yield {...}
    

    Est traduit sur Scala 2.7 en

    c.filter(x => cond).map(x => {...})
    

    Ou, sur Scala 2.8, dans

    c.withFilter(x => cond).map(x => {...})
    

    Avec un repli dans l'ancienne méthode if withFilter n'est pas disponible mais filter l'est. Veuillez consulter la section ci-dessous pour plus d'informations à ce sujet.

  4. Ce

    for(x <- c; y = ...) yield {...}
    

    Est traduit en

    c.map(x => (x, ...)).map((x,y) => {...})
    

Lorsque vous regardez des compréhensions très simples for, le map/foreach les alternatives semblent, en effet, mieux. Une fois que vous commencez à les composer, cependant, vous pouvez facilement obtenir perdu entre parenthèses et les niveaux d'imbrication. Lorsque cela se produit, for compréhensions sont généralement beaucoup plus claires.

Je vais montrer un exemple simple, et intentionnellement omettre toute explication. Vous pouvez décider quelle syntaxe était plus facile à comprendre.

l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))

Ou

for {
  sl <- l
  el <- sl
  if el > 0
} yield el.toString.length

withFilter

Scala 2.8 a introduit une méthode appelée withFilter, dont la principale différence est que, au lieu de renvoyer une nouvelle collection filtrée, elle filtre à la demande. La méthode filter a son comportement défini en fonction de la rigueur de la collection. Pour mieux comprendre cela, jetons un coup D'oeil à certains Scala 2.7 avec List (strict) et Stream (non-strict):

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

La différence se produit parce que filter est immédiatement appliqué avec List, renvoyant une liste de cotes-puisque found est false. Seulement alors foreach est exécuté, mais, à ce moment-là, changer found n'a pas de sens, comme filter l'a déjà exécuté.

Dans le cas de Stream, la condition n'est pas immédiatement appliquées. Au lieu de cela, comme chaque élément est demandé par foreach, filter teste la condition, ce qui permet à foreach de l'influencer à travers found. Juste pour être clair, voici l'équivalent pour le code de compréhension:

for (x <- List.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

for (x <- Stream.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

Cela a causé beaucoup de problèmes, car les gens s'attendaient à ce que le if soit considéré à la demande, au lieu d'être appliqué à l'ensemble de la collection au préalable.

Scala 2.8 introduit withFilter, qui est toujours non-stricte, peu importe la sévérité de la collection. L'exemple suivant montre List, avec les deux méthodes sur Scala 2.8:

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

Cela produit le résultat que la plupart des gens attendent, sans changer le comportement de filter. Comme note de côté, Range a été changé de non-strict à strict entre Scala 2.7 et Scala 2.8.

776
répondu Daniel C. Sobral 2018-07-30 16:24:29

Oui, comme l'a dit Earwicker, c'est à peu près l'équivalent de select de LINQ et a très peu à voir avec yield de Ruby et de Python. Fondamentalement, où en C# vous écririez

from ... select ??? 

Dans Scala vous avez à la place

for ... yield ???

Il est également important de comprendre que for - compréhensions ne fonctionnent pas seulement avec des séquences, mais avec tout type qui définit certaines méthodes, tout comme LINQ:

  • Si votre type ne définit que map, il autorise for - des expressions composées de un seul générateur.
  • , Si elle définit flatMap ainsi que map, il permet de for-expressions composé de plusieurs générateurs.
  • s'il définit foreach, il permet for - boucles sans rendement (à la fois avec des générateurs simples et multiples).
  • s'il définit filter, il autorise for - filtrer les expressions commençant par un if dans l'expression for.
23
répondu Alexey Romanov 2012-04-11 14:07:12

Le mot-clé yield dans Scala est simplement du sucre syntaxique, qui peut être facilement remplacé par un map, comme Daniel Sobral déjà expliqué dans le détail.

D'autre part, yield est absolument trompeur si vous recherchez des générateurs (ou des continuations) similaires à ceux de Python . Voir ce thread SO Pour plus d'Informations: Quel est le moyen préféré d'implémenter 'yield' dans Scala?

12
répondu Richard Gomes 2017-05-23 10:31:32

Sauf si vous obtenez une meilleure réponse d'un utilisateur Scala (ce que je ne suis pas), voici ma compréhension.

, Il n'apparaît que comme une partie d'une expression commençant par for, qui indique comment générer une nouvelle liste à partir d'une liste existante.

Quelque Chose comme:

var doubled = for (n <- original) yield n * 2

Il y a donc un élément de sortie pour chaque entrée (bien que je crois qu'il existe un moyen de supprimer les doublons).

Ceci est tout à fait différent des "continuations impératives" activées par yield dans d'autres langues, où il fournit un moyen de générer une liste de n'importe quelle longueur, à partir d'un code impératif avec presque n'importe quelle structure.

(Si vous êtes familier avec C#, il est plus proche de LINQ select opérateur que c'est à yield return).

12
répondu Daniel Earwicker 2014-02-17 16:27:18

Considérez ce qui suit pour-compréhension

val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i

, Il peut être utile de le lire à haute voix comme suit

"Pour chaque entier i, if, il est plus grand que 3, puis rendement (produire) i et l'ajouter à la liste A."

En termes de notation mathématique set-builder , LA for-compréhension ci-dessus est analogue à

Qui peut être interprété comme

"Pour chaque entier , si, il est supérieur , alors il est un membre de l'ensemble ."

Ou alternativement comme

" est l'ensemble de tous les entiers, tels que chacun est supérieur à ."

9
répondu Mario Galic 2017-02-08 15:07:41
val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1
val res4 = aList.filter(_ > 3).map(_ + 1)

println( res3 )
println( res4 )

Ces deux éléments de code sont équivalents.

val res3 = for (al <- aList) yield al + 1 > 3
val res4 = aList.map( _+ 1 > 3 )

println( res3 ) 
println( res4 )

Ces deux éléments de code sont également équivalents.

La carte est aussi flexible que le rendement et vice-versa.

0
répondu dotnetN00b 2013-10-25 23:59:31

Yield est similaire à For loop qui a un tampon que nous ne pouvons pas voir et pour chaque incrément, il continue d'ajouter l'élément suivant au tampon. Lorsque la boucle for se termine, elle renvoie la collection de toutes les valeurs générées. Yield peut être utilisé comme opérateurs arithmétiques simples ou même en combinaison avec des tableaux. Voici deux exemples simples pour une meilleure compréhension

scala>for (i <- 1 to 5) yield i * 3

Res: scala.collection.immuable.IndexedSeq[Int] = Vecteur(3, 6, 9, 12, 15)

scala> val nums = Seq(1,2,3)
nums: Seq[Int] = List(1, 2, 3)

scala> val letters = Seq('a', 'b', 'c')
letters: Seq[Char] = List(a, b, c)

scala> val res = for {
     |     n <- nums
     |     c <- letters
     | } yield (n, c)

Res: Seq[(Int, Char)] = List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))

Espérons que cela aide!!

0
répondu Manasa Chada 2018-08-12 12:02:32

Le rendement est plus flexible que map (), Voir l'exemple ci-dessous

val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1 
val res4 = aList.map( _+ 1 > 3 ) 

println( res3 )
println( res4 )

Yield affichera le résultat comme: List (5, 6), ce qui est bon

While map() retournera le résultat comme: List(false, false, true, true, true), ce qui n'est probablement pas ce que vous avez l'intention.

-2
répondu Michael Peng 2013-10-10 18:24:46