PySpark DataFrame将Array of Struct转为列(避免行重复)
解决方案
完全可以实现这种转换,不需要用explode拆分行。核心思路是把数组列转换成键值对Map,再从Map中提取对应字段的值,这样就能在原行基础上新增列,不会产生重复行。
步骤说明
- 用
map_from_entries函数将数组中的元素(每个元素是[id, value]的数组或struct)转换为Map类型,键是id,值是对应的value。 - 对Map使用
getItem方法提取"PHONE"、"FAX"、"MAIL"对应的值,自动处理不存在的键(返回null),同时兼容原数组为null的情况。
代码示例
首先创建示例DataFrame:
from pyspark.sql import SparkSession from pyspark.sql.functions import map_from_entries, col spark = SparkSession.builder.appName("array_to_columns").getOrCreate() data = [ (1, [["PHONE", "083665xxxx"], ["FAX", "0325xxxxxx"]]), (2, [["MAIL", "abc@xxx.com"]]), (3, None) ] df = spark.createDataFrame(data, ["technical_id", "column_to_explode"])
执行转换逻辑:
# 转换数组为Map,处理null情况 df_transformed = df.withColumn( "contact_map", map_from_entries(col("column_to_explode")) ).select( "technical_id", "column_to_explode", col("contact_map").getItem("PHONE").alias("PHONE"), col("contact_map").getItem("FAX").alias("FAX"), col("contact_map").getItem("MAIL").alias("MAIL") ).drop("contact_map") df_transformed.show()
输出结果
+-------------+--------------------+-----------+-----------+-------------+ |technical_id| column_to_explode| PHONE| FAX| MAIL| +-------------+--------------------+-----------+-----------+-------------+ | 1|[["PHONE", "08366...|083665xxxx|0325xxxxxx| null| | 2|[["MAIL", "abc@xx...| null| null|abc@xxx.com| | 3| null| null| null| null| +-------------+--------------------+-----------+-----------+-------------+
适配原始struct结构的说明
如果你的原始数据结构是array of struct(即column_to_explode是包含id和value字段的struct数组),map_from_entries可以直接接收该类型,无需额外转换,代码逻辑和上述一致:
# 假设原始列是struct数组,结构为array<struct<id:string, value:string>> df_transformed = df.withColumn( "contact_map", map_from_entries(col("column_to_explode")) ).select( "technical_id", "column_to_explode", col("contact_map").getItem("PHONE").alias("PHONE"), col("contact_map").getItem("FAX").alias("FAX"), col("contact_map").getItem("MAIL").alias("MAIL") ).drop("contact_map")
内容的提问来源于stack exchange,提问作者tpx
相关产品推荐
相关产品推荐

