2 votes

Scala - Joindre une liste de tuples par clé

Je cherche un moyen de joindre deux listes de tuples en scala pour obtenir le même résultat qu'Apache spark me donne en utilisant la fonction join. Exemple : Avoir deux listes de tuples comme nous :

val l1 = List((1,1),(1,2),(2,1),(2,2))
l1: List[(Int, Int)] = List((1,1), (1,2), (2,1), (2,2))

val l2 = List((1,(1,2)), (2,(2,3)))
l2: List[(Int, (Int, Int))] = List((1,(1,2)), (2,(2,3)))

Quelle est la meilleure façon de joindre par clé les deux listes pour obtenir le résultat suivant ?

l3: List[(Int,(Int,(Int,Int)))] = ((1,(1,(1,2))),(1,(2,(1,2))),(2,(1,(2,3))),(2,(2,(2,3))))

8voto

Andrei T. Points 1882

Vous pouvez utiliser un pour la compréhension et tirer parti de l'utilisation du '`' dans la correspondance des motifs. C'est-à-dire qu'il ne correspondra que si les clés de la première liste sont les mêmes que celles de la deuxième liste ("`k`" signifie que la clé du tuple doit être égale à la valeur de k).

val res = for {
  (k, v1)   <- l1
  (`k`, v2) <- l2
} yield (k, (v1, v2))

J'espère que vous trouverez cela utile.

1voto

Thomas Böhm Points 1115

Vous pourriez vouloir faire quelque chose comme ça :

val l3=l1.map(tup1 => l2.filter(tup2 => tup1._1==tup2._1).map(tup2 => (tup1._1, (tup1._2, tup2._2)))).flatten

Elle fait correspondre les mêmes index, crée des sous-listes, puis combine la liste des listes avec la fonction flatten -commande

Cela aboutit à :

List((1,(1,(1,2))), (1,(2,(1,2))), (2,(1,(2,3))), (2,(2,(2,3))))

0voto

Jarek Points 141

Essayez quelque chose comme ça :

val l2Map = l2.toMap
val l3 = l1.flatMap { case (k, v1) => l2Map.get(k).map(v2 => (k, (v1, v2))) }

ce qui peut être réécrit sous une forme plus générale en utilisant des implicites :

package some.package

import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom

package object collection {

  implicit class PairTraversable[K, V, C[A] <: TraversableLike[A, C[A]]](val seq: C[(K, V)]) {

    def join[V2, C2[A] <: TraversableLike[A, C2[A]]](other: C2[(K, V2)])
                                                    (implicit canBuildFrom: CanBuildFrom[C[(K, V)], (K, (V, V2)), C[(K, (V, V2))]]): C[(K, (V, V2))] = {
      val otherMap = other.toMap
      seq.flatMap { case (k, v1) => otherMap.get(k).map(v2 => (k, (v1, v2))) }
    }
  }
}

et puis simplement :

import some.package.collection.PairTraversable

val l3 = l1.join(l2)

Cette solution convertit la deuxième séquence en carte (elle consomme donc un peu de mémoire supplémentaire), mais elle est beaucoup plus rapide que les solutions proposées dans les autres réponses (comparez-la pour de grandes collections, par exemple 10000 éléments, sur mon ordinateur portable, elle est de 5 ms contre 2500 ms).

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