You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Polars中遍历StructChunked?求JSON转换实现方案

Polars扩展:Struct转JSON的实现修正

我正在为Python Polars库开发扩展,目标是实现将Struct转换为JSON的功能——用结构体字段作为键、对应值作为JSON值。但处理StructChunked比Python层面的pl.struct困难很多,现有代码无法编译,希望得到实现建议或代码示例。

无法编译的原代码

use polars::prelude::*;
use pyo3_polars::derive::polars_expr;
use serde_json::*;

#[polars_expr(output_type=Utf8)]
fn to_json(inputs: &[Series]) -> PolarsResult<Series> {
    let ca: &StructChunked = inputs[0].struct_()?;
    let out: Utf8Chunked = ca
        .into_iter()
        .map(|row| serde_json::to_string(row).unwrap())
        .collect();
    Ok(out.into_series())
}

问题分析

原代码存在几个核心问题:

  • StructChunked迭代器返回的是Option<StructValue>,而StructValue未实现serde::Serialize,无法直接用serde_json::to_string序列化。
  • 直接使用unwrap()会引发Panic,不符合Polars的错误处理规范。
  • collect()无法直接将迭代器转换为Utf8Chunked,需要显式构建。

修正后的实现代码

use polars::prelude::*;
use pyo3_polars::derive::polars_expr;
use serde_json::Value as JsonValue;
use base64;

#[polars_expr(output_type=Utf8)]
fn to_json(inputs: &[Series]) -> PolarsResult<Series> {
    let ca: &StructChunked = inputs[0].struct_()?;
    let mut builder = Utf8ChunkedBuilder::new(ca.name(), ca.len());

    for opt_struct in ca.into_iter() {
        let json_str = match opt_struct {
            Some(s) => {
                let mut json_map = serde_json::Map::new();
                // 遍历结构体字段与对应列的值
                for (field_name, series) in ca.fields().iter().zip(ca.columns()) {
                    let value = series.get(s.index());
                    let json_val = value_to_json(value)?;
                    json_map.insert(field_name.clone(), json_val);
                }
                serde_json::to_string(&JsonValue::Object(json_map))?
            }
            None => String::from("null"),
        };
        builder.append_value(json_str);
    }

    Ok(builder.finish().into_series())
}

// 辅助函数:将Polars AnyValue转换为serde_json::Value
fn value_to_json(value: AnyValue<'_>) -> PolarsResult<JsonValue> {
    match value {
        AnyValue::Null => Ok(JsonValue::Null),
        AnyValue::Boolean(b) => Ok(JsonValue::Bool(b)),
        AnyValue::UInt8(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::UInt16(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::UInt32(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::UInt64(v) => Ok(JsonValue::Number(serde_json::Number::from(v))),
        AnyValue::Int8(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::Int16(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::Int32(v) => Ok(JsonValue::Number(v.into())),
        AnyValue::Int64(v) => Ok(JsonValue::Number(serde_json::Number::from(v))),
        AnyValue::Float32(v) => Ok(JsonValue::Number(serde_json::Number::from_f64(v.into()).ok_or_else(|| {
            PolarsError::ComputeError("Failed to convert f32 to JSON number".into())
        })?)),
        AnyValue::Float64(v) => Ok(JsonValue::Number(serde_json::Number::from_f64(v).ok_or_else(|| {
            PolarsError::ComputeError("Failed to convert f64 to JSON number".into())
        })?)),
        AnyValue::Utf8(s) => Ok(JsonValue::String(s.to_string())),
        AnyValue::Binary(b) => Ok(JsonValue::String(base64::encode(b))),
        AnyValue::List(l) => {
            let mut json_arr = Vec::new();
            for elem in l.iter() {
                json_arr.push(value_to_json(elem)?);
            }
            Ok(JsonValue::Array(json_arr))
        }
        AnyValue::Struct(s) => {
            let mut json_map = serde_json::Map::new();
            for (field_name, field_value) in s.iter() {
                json_map.insert(field_name.to_string(), value_to_json(field_value)?);
            }
            Ok(JsonValue::Object(json_map))
        }
        other => Err(PolarsError::ComputeError(format!(
            "Unsupported data type for JSON serialization: {:?}",
            other
        ))),
    }
}

关键实现说明

  • 使用Utf8ChunkedBuilder高效构建结果字符串列,这是Polars处理字符串列的标准做法。
  • 手动遍历结构体字段与对应列,将每个AnyValue转换为JSON兼容格式,支持嵌套结构体、列表等复杂类型。
  • 用PolarsResult统一处理错误,避免Panic,符合Polars的错误处理机制。
  • 辅助函数value_to_json覆盖了常见Polars数据类型的转换,可根据需求扩展更多类型支持。

内容的提问来源于stack exchange,提问作者H.yk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:22:36