
本文介绍如何使用 Polars 的链式表达式,在单次 with_columns 调用中,将两个等长列表列(如 Movie 和 Count)按位置配对,并自动跳过任一元素为 null 的项,最终生成一个 struct 类型的配对结果列。
本文介绍如何使用 polars 的链式表达式,在单次 `with_columns` 调用中,将两个等长列表列(如 movie 和 count)按位置配对,并自动跳过任一元素为 `null` 的项,最终生成一个 struct 类型的配对结果列。
在 Polars 中处理嵌套列表时,常需对齐、过滤并结构化多列数据。本例中,目标是将 Movie 和 Count 两列的对应元素(索引一致)组成键值对,但仅保留双方均非空的配对——即跳过 Movie[i] 或 Count[i] 任一为 null 的位置。关键约束是:整个操作必须在单个 with_columns 内完成,避免中间物化或多次扫描。
实现的核心思路是:
- 定位有效索引:对 Movie 列调用 .list.eval(pl.element().is_not_null().arg_true()),返回所有非空元素的下标(如 [1]);
- 同步筛选两列:用 .list.gather(...) 同时提取 Movie 和 Count 在这些下标处的元素,确保严格对齐;
- 构造结构体:将筛选后的两列传入 pl.struct(),自动生成 struct[2] 类型字段(字段名默认继承原列名)。
以下是完整可运行代码:
import polars as pl
df = pl.DataFrame({
"Movie": [[None, "IT", "Joker"]],
"Count": [[30, 27, None]],
})
result = df.with_columns(
pl.struct(
pl.col("Movie", "Count")
.list.gather(
pl.col("Movie").list.eval(pl.element().is_not_null().arg_true())
)
.list.first()
).alias("data")
)
print(result.select("data"))输出:
shape: (1, 1)
┌───────────┐
│ data │
│ --- │
│ struct[2] │
╞═══════════╡
│ {"IT",27} │
└───────────┘⚠️ 注意事项:
- list.gather() 要求索引列与被筛选列长度一致,此处因 Movie 和 Count 等长且同属一行,安全可用;
- .list.first() 是必需的:list.gather() 返回的是嵌套列表(如 [[["IT"], [27]]]),需解包一层;
- 若需自定义 struct 字段名(如 "title" / "views"),可显式指定:pl.struct(pl.col("Movie").alias("title"), pl.col("Count").alias("views"));
- 此方案天然支持多行数据(每行独立处理),无需 group_by 或 apply,性能高效。
总结:Polars 的 list.eval + list.gather 组合提供了强大的列表级向量化过滤能力,配合 struct 可在单表达式内完成复杂嵌套对齐任务,是处理 JSON-like 列的推荐范式。

















