PySpark:如何将指定列转为含列名key的结构体数组
Spark中生成包含列名作为Key的结构体数组
问题根源
你之前的写法存在两个核心问题:
TRANSFORM(array(name, age), col -> ...)里的array(name, age)生成的是列值的数组,没有携带列名元信息,迭代过程中无法获取原列名。- 使用f-string的
{col}时,Python会优先尝试解析本地变量col,但col是SQL表达式内的迭代变量,Python上下文不存在该变量,因此抛出NameError。
正确实现方式
1. 固定列名场景
直接为每个目标列构造包含列名字面量和对应值的结构体,再将这些结构体组合成数组:
df_with_column_of_structs = df.withColumn( 'array_of_structs', expr("array(named_struct('key', 'name', 'val', name), named_struct('key', 'age', 'val', age))") )
2. 动态传入列名字符串列表场景
如果需要通过列名列表(比如cols = ['name', 'age'])动态生成,可通过字符串拼接构造SQL表达式:
cols = ['name', 'age'] # 生成每个列对应的named_struct语句 struct_exprs = [f"named_struct('key', '{col}', 'val', {col})" for col in cols] # 组合成完整的array表达式 array_expr = f"array({','.join(struct_exprs)})" df_with_column_of_structs = df.withColumn('array_of_structs', expr(array_expr))
验证输出
执行上述代码后,show()的输出将符合预期:
+-------+---+-----------+---------------------------+ |name |age|city |array_of_structs | +-------+---+-----------+---------------------------+ |Alice |30 |New York |[{name, Alice}, {age, 30}] | |Bob |25 |Los Angeles|[{name, Bob}, {age, 25}] | |Charlie|35 |Chicago |[{name, Charlie}, {age, 35}]| +-------+---+-----------+---------------------------+
补充:TRANSFORM的冗余写法
如果一定要使用TRANSFORM,需要先构造包含列名和值的配对数组,再迭代生成结构体(此方式灵活性不如上述方案):
df_with_column_of_structs = df.withColumn( 'array_of_structs', expr("TRANSFORM(array((name, 'name'), (age, 'age')), x -> named_struct('key', x._2, 'val', x._1))") )
内容的提问来源于stack exchange,提问作者219CID
相关产品推荐
相关产品推荐

