2 votes

Accès à la sortie précédente lors du chaînage d'opérateurs en Scala

Comment accéder à la valeur de sortie résultante pour effectuer une prochaine opération par exemple :

scala> List(1,4,3,4,4,5,6,7)
res0: List[Int] = List(1, 4, 3, 4, 4, 5, 6, 7)

scala> res0.removeDuplicates.slice(0, ???.size -2)

Dans la ligne ci-dessus, je dois effectuer une opération de découpage après avoir supprimé les doublons. Pour ce faire, comment accéder à la sortie de .removeDuplicate() pour que je puisse l'utiliser pour trouver size pour le fonctionnement en tranches.

J'ai besoin d'effectuer cette opération en une seule étape. Pas en plusieurs étapes comme :

scala> res0.removeDuplicates
res1: List[Int] = List(1, 4, 3, 5, 6, 7)

scala> res1.slice(0, res1.size -2)
res2: List[Int] = List(1, 4, 3, 5)

Je veux accéder aux résultats intermédiaires dans l'opération finale. removeDuplicates() n'est qu'un exemple.

list.op1().op2().op3().finalop() Ici, je veux accéder à : la sortie de op1 , op2 , op3 sur finalop

4voto

Dima Points 7274

Enveloppe dans un Option peut être une option (sans jeu de mots) :

val finalResult = Some(foo).map { foo => 
  foo.op1(foo.stuff)
}.map { foo => 
  foo.op2(foo.stuff)
}.map { foo => 
  foo.op3(foo.stuff)
}.get.finalOp

Vous pouvez rendre la partie de l'emballage implicite pour la rendre un peu plus belle :

object Tapper {
  implicit class Tapped[T] extends AnyVal(val v: T) {
     def tap[R](f: T => R) = f(v)
  }
}

import Tapper._
val finalResult = foo
 .tap(f => f.op1(f.stuff))
 .tap(f => f.op2(f.stuff))
 .tap(f => f.finalOp(f.stuff))

4voto

dkolmakov Points 553

Avec pour la compréhension il est possible de composer des opérations de manière tout à fait lisible avec la possibilité d'accéder aux résultats intermédiaires :

val res = for {
  ls1 <- Option(list.op1)
  ls2 = ls1.op2()           // Possible to access list, ls1
  ls3 = ls2.op3()           // Possible to access list, ls1, ls2
} yield ls4.finalOp()       // Possible to access list, ls1, ls2, ls3

Par exemple :

scala> val ls = List(1,1,2,2,3,3,4,4)
ls: List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)

scala> :paste
// Entering paste mode (ctrl-D to finish)

for {
  ls1 <- Option(ls.map(_ * 2))
  ls2 = ls1.map(_ + ls1.size)
  ls3 = ls2.filter(_ < ls1.size + ls2.size)
} yield ls3.sum

// Exiting paste mode, now interpreting.

res15: Option[Int] = Some(72)

1voto

radumanolescu Points 2350

Vous n'aurez pas besoin de connaître la longueur si vous utilisez dropRight :

scala> val a = List(1,4,3,4,4,5,6,7)
a: List[Int] = List(1, 4, 3, 4, 4, 5, 6, 7)

scala> a.dropRight(2)
res0: List[Int] = List(1, 4, 3, 4, 4, 5)

Alors fais ça : res0.removeDuplicates.dropRight(2)

1voto

Eric M. Points 473

Si vous en avez vraiment besoin dans une seule fonction, vous pouvez écrire une fonction personnalisée de foldLeft quelque chose comme ça :

var count = 0
val found = new HashSet()
res0.foldLeft(List[Int]()) { (z, i) =>
    if(!found.contains(i)){
        if(count < 4){
            z :+ i
            found += i
            count += 1
        }
    }
}

Cependant, je ne vois pas vraiment le problème de chaîner les appels comme dans res0.removeDuplicates.slice . L'un des avantages de la programmation fonctionnelle est que notre compilateur peut optimiser les situations de ce type où nous voulons simplement un certain comportement et ne voulons pas spécifier l'implémentation.

1voto

radumanolescu Points 2350

Vous voulez traiter des données à travers une série de transformations : someData -> op1 -> op2 -> op3 -> finalOp. Cependant, à l'intérieur de l'op3, vous voudriez avoir accès aux résultats intermédiaires du traitement effectué dans l'op1. La clé ici est de transmettre à la fonction suivante dans la chaîne de traitement toutes les informations qui seront nécessaires en aval.

Disons que votre entrée est xs: Seq[String] et op1 est de type (xs: Seq[String]) => Seq[String] . Vous voulez modifier l'opération 1 pour qu'elle renvoie case class ResultWrapper(originalInputLength: Int, deduplicatedItems: Seq[String], somethingNeededInOp5: SomeType) . Si toutes vos opérations transmettent ce dont les autres opérations ont besoin en aval, vous obtiendrez ce dont vous avez besoin. Ce n'est pas très élégant, car il existe un couplage entre vos opérations : l'amont doit sauvegarder les informations dont l'aval a besoin. À ce stade, ce ne sont plus vraiment des "opérations différentes".

Une chose que vous pouvez faire est d'utiliser une Map[A,B] comme votre "enveloppe de résultat". De cette façon, il y a moins de couplage entre les opérations, mais aussi moins de sécurité de type.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X