Question

J'ai un for-comprehension avec un générateur à partir d'un Set[MyType] Cette MyType a un lazy val variable appelée factsPair qui renvoie une paire d'ensembles:(Réglez[MyFact], Réglez[MyFact]).

Je souhaite faire une boucle par tous et unifier les faits dans un aplatie paire (Set[MyFact], Réglez[MyFact]), comme suit, et pourtant je suis arriver No implicit view available ... et not enough arguments for flatten: implicit (asTraversable ... erreurs.(Je suis un peu nouveau pour Scala encore en train de s'habituer à l'erreur).

lazy val allFacts  =
(for {
  mytype <- mytypeList
} yield mytype.factsPair).flatten

De quoi ai-je besoin de préciser pour aplatir pour que cela fonctionne?

Était-ce utile?

La solution

Vous ne serez pas en mesure d'utiliser flatten pour cela, parce que flatten sur une collection renvoie une collection, et un tuple n'est pas une collection.

Vous pouvez, bien sûr, il suffit de diviser, aplatir, et de joindre à nouveau:

val pairs = for {
  mytype <- mytypeList
} yield mytype.factsPair
val (first, second) = pairs.unzip
val allFacts = (first.flatten, second.flatten)

Autres conseils

Scala aplatir fonctionne sur les mêmes types.Vous avez un Seq[(Set[MyFact], Réglez[MyFact])], qui ne peut être aplati.

Je recommande l'apprentissage de la foldLeft fonction, parce que c'est très général et très facile à utiliser dès que vous obtenez le coup de lui:

lazy val allFacts = myTypeList.foldLeft((Set[MyFact](), Set[MyFact]())) {
  case (accumulator, next) =>
    val pairs1 = accumulator._1 ++ next.factsPair._1
    val pairs2 = accumulator._2 ++ next.factsPair._2
    (pairs1, pairs2)
}

Le premier paramètre prend le premier élément, il va ajouter les autres éléments.Nous commençons avec un vide Tuple[Set[MyFact], Set[MyFact]] initialisé comme ceci: (Set[MyFact](), Set[MyFact]()).

Ensuite, nous avons à spécifier la fonction qui prend l'accumulateur et l'ajoute à l'élément suivant et revient avec la nouvelle batterie qui a les prochaines élément en elle.En raison de tous les n-uplets, il n'a pas l'air gentil, mais il fonctionne.

Un tuple n'est pas traverable, de sorte que vous ne pouvez pas aplatir sur elle.Vous avez besoin de retourner quelque chose qui peut être itéré, comme une Liste, par exemple:

List((1,2), (3,4)).flatten          // bad
List(List(1,2), List(3,4)).flatten  // good

Je tiens à offrir une plus algébrique vue.Ici, vous avez peut être bien résolu à l'aide de monoids.Pour chaque monoïde il y a un zéro de l'élément et une opération de combiner deux éléments en un seul.

Dans ce cas, les ensembles pour un monoïde:le zéro de l'élément est un ensemble vide et le fonctionnement de l'union.Et si nous avons deux monoids, leur produit Cartésien est aussi un monoïde, où les opérations sont définies par paires (voir exemples sur Wikipédia).

Scalaz définit monoids pour des ensembles de n-uplets, donc nous n'avons pas besoin de faire quoi que ce soit là.Nous allons juste besoin d'une fonction d'assistance qui combine plusieurs monoïde éléments en un seul, qui est mis en œuvre facilement à l'aide de pliage:

def msum[A](ps: Iterable[A])(implicit m: Monoid[A]): A =
  ps.foldLeft(m.zero)(m.append(_, _))

(peut-être qu'il y a déjà une telle fonction dans Scala, je n'ai pas trouver).À l'aide de msum on peut facilement définir

def pairs(ps: Iterable[MyType]): (Set[MyFact], Set[MyFact]) =
  msum(ps.map(_.factsPair))

à l'aide de Scalaz implicite de monoids pour les tuples et les décors.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top