J'ai plusieurs Map [String, String]
dans une List
(Scala). Par exemple:
EMP_NAME DOB CITY Ahmad 01-10-1991 Dubai Rahul 06-12-1991 Mumbai John 11-04-1996 Toronto
Maintenant, je veux créer une seule dataframe avec quelque chose comme ceci:
map1 = Map("EMP_NAME" -> âAhmadâ, "DOB" -> â01-10-1991â, "CITY" -> âDubaiâ) map2 = Map("EMP_NAME" -> âRahulâ, "DOB" -> â06-12-1991â, "CITY" -> âMumbaiâ) map3 = Map("EMP_NAME" -> âJohnâ, "DOB" -> â11-04-1996â, "CITY" -> âTorontoâ) list = List(map1, map2, map3)
Comment puis-je y parvenir? p>
3 Réponses :
vous pouvez le faire comme ceci:
import spark.implicits._ val df = list .map( m => (m.get("EMP_NAME"),m.get("DOB"),m.get("CITY"))) .toDF("EMP_NAME","DOB","CITY") df.show() +--------+----------+-------+ |EMP_NAME| DOB| CITY| +--------+----------+-------+ | Ahmad|01-10-1991| Dubai| | Rahul|06-12-1991| Mumbai| | John|11-04-1996|Toronto| +--------+----------+-------+
Approche légèrement moins spécifique, par exemple:
val RDDmap = sc.parallelize(List( Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai"), Map("EMP_NAME" -> "John", "DOB" -> "01-10-1992", "CITY" -> "Mumbai"))) ... // Get cols dynamically val cols = RDDmap.take(1).flatMap(x=> x.keys) // Map is K,V like per Map entry val df = RDDmap.map{ value=> val list=value.values.toList (list(0), list(1), list(2)) }.toDF(cols:_*) // dynamic column names assigned
renvoie:
+--------+----------+------+ |EMP_NAME|DOB |CITY | +--------+----------+------+ |Ahmad |01-10-1991|Dubai | |John |01-10-1992|Mumbai| +--------+----------+------+
ou pour répondre à votre sous-question, ici comme suit - au moins je pense que c'est ce que vous demandez, mais probablement pas:
val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai") val map2 = Map("EMP_NAME" -> "John", "DOB" -> "01-10-1992", "CITY" -> "Mumbai") ///... val list = List(map1, map2) // map3, ... val RDDmap = sc.parallelize(list) // Get cols dynamically val cols = RDDmap.take(1).flatMap(x=> x.keys) // Map is K,V like per Map entry val df = RDDmap.map{ value=> val list=value.values.toList (list(0), list(1), list(2)) }.toDF(cols:_*) // dynamic column names assigned df.show(false)
Vous pouvez bien sûr construire une liste dynamiquement, mais vous devez toujours attribuer les éléments de la carte. Voir Ajouter des données à la liste ou à toute autre collection de manière dynamique dans scala . Je voudrais simplement lire un fichier et en finir.
Merci l'homme Un autre point: comment faire une boucle dynamique (list (0), list (1), list (2))? je veux dire au lieu de coder en dur 1,2 et 3, peut-il prendre quelque chose comme la liste (i)?
Réponse mise à jour qui est en fait une autre réponse. Veuillez accepter le contraire.
@thebluephantom, je ne suppose pas que les résultats de .keys
et .values
d'une Map
conserveront toujours l'ordre par paire KV.
@LeoC Veuillez préciser
Si m = Map (1-> a, 2-> b, ...)
, je pense qu'il n'est pas prudent de supposer m.keys
et m. les valeurs
auront à coup sûr leurs éléments classés comme 1, 2, ...
et a, b, ...
, respectivement, ni comme La carte
ni Set
préserve l'ordre.
@LeoC Voulez-vous dire que des lignes qui sont bien comprises comme étant un problème, peuvent s'appliquer aux coks gere pendant flatMap?
@LeoC J'ai regardé tutorialspoint.com/scala/scala_maps.htm et ils ont un exemple similaire, aucune mention de votre point là. Je me souviens avoir étudié cela il y a quelque temps.
@LeoC Juste pour la postérité, pas convaincu que l'exemple ici est une utilisation classique de la carte.
@thebluephantom, mon point est que puisque les éléments dans m.keys
et m.values
ne peuvent pas être garantis de conserver l'ordre dans la paire KV d'origine, il est possible que le jeu de données résultant pourrait être quelque chose comme Seq (("a", "c", "b", "d")). toDF ("2", "1", "3", "4")) code >.
@LeoC comment cela pourrait-il arriver? cela signifie que tutorialspoints a un mauvais exemple. qu'en est-il alors d'obtenir des cols à partir de dataframes?
Parce que Map
ne préserve pas l'ordre. par exemple. Carte (1 -> "a", 2 -> "b") == Carte (2 -> "b", 1 -> "a")
, mais Carte (1- > "a", 2 -> "b"). keys.toList! = Map (2 -> "b", 1 -> "a"). keys.toList
.
J'ai compris. Cela signifie donc 2 choses, le point du tutoriel que j'ai regardé dans le passé est faux et mon point précédent est de toute façon un mauvais exemple de cas d'utilisation de Map.
import org.apache.spark.SparkContext import org.apache.spark.sql._ import org.apache.spark.sql.types.{StringType, StructField, StructType} object DataFrameTest2 extends Serializable { var sparkSession: SparkSession = _ var sparkContext: SparkContext = _ var sqlContext: SQLContext = _ def main(args: Array[String]): Unit = { sparkSession = SparkSession.builder().appName("TestMaster").master("local").getOrCreate() sparkContext = sparkSession.sparkContext val sqlContext = new org.apache.spark.sql.SQLContext(sparkContext) val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai") val map2 = Map("EMP_NAME" -> "Rahul", "DOB" -> "06-12-1991", "CITY" -> "Mumbai") val map3 = Map("EMP_NAME" -> "John", "DOB" -> "11-04-1996", "CITY" -> "Toronto") val list = List(map1, map2, map3) //create your rows val rows = list.map(m => Row(m.values.toSeq:_*)) //create the schema from the header val header = list.head.keys.toList val schema = StructType(header.map(fieldName => StructField(fieldName, StringType, true))) //create your rdd val rdd = sparkContext.parallelize(rows) //create your dataframe using rdd val df = sparkSession.createDataFrame(rdd, schema) df.show() } }
Le protocole est que vous sélectionnez l'une des autres réponses comme étant correcte, à moins que personne d'autre ne l'ait fourni ou que vous estimiez qu'elle était inappropriée.
Je pense que toutes les réponses sont correctes dans ce contexte. Le vôtre et le premier aussi. Je ne sais pas comment marquer plusieurs réponses correctes. De plus, je cherchais simplement la solution la plus générique. En réalité, je vais créer et remplir dynamiquement un ensemble de données pour plus de 40 colonnes. Au fait, j'apprécie beaucoup la solution que vous avez apportée :)
Ensuite, veuillez l'accepter car il est plus flexible, pour l'approche 40 cols. Mais vous pouvez voter pour. Le choix t'appartient.
J'ai voté plusieurs fois pour votre réponse. Mais voici le message que je reçois: Merci pour les commentaires! Les votes exprimés par ceux qui ont moins de 15 points de réputation sont enregistrés, mais ne modifient pas le score affiché publiquement. :( On dirait que je dois d'abord bâtir ma réputation :)
C'est vrai, c'est le cas. Vous pouvez alors accepter la réponse uniquement, si vous pensez que c'est la meilleure, faites-le, sinon choisissez l'autre.
Je ne sais pas comment choisir. Je ne vois aucune étiquette / bouton pour accéder à la réponse. Y a-t-il un lien?
Cliquez simplement sur la coche grise et elle deviendra verte. Vous ne pouvez en choisir qu'un.