Skip to content

Commit cc5383a

Browse files
authored
feat: Adding struct jsonEncode (#377)
Adding struct jsonEncode to close #376 Co-authored-by: Bidek56 <[email protected]>
1 parent 13181a1 commit cc5383a

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

__tests__/expr.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable newline-per-chained-call */
2+
23
import pl, { col, lit } from "@polars/index";
34

45
const df = () => {
@@ -1469,6 +1470,23 @@ describe("expr.str", () => {
14691470
);
14701471
expect(actual).toFrameStrictEqual(expected);
14711472
});
1473+
test("struct:renameFields", () => {
1474+
const actual = pl
1475+
.DataFrame({
1476+
objs: [
1477+
{ a: 1, b: 2.0, c: "abc" },
1478+
{ a: 10, b: 20.0, c: "def" },
1479+
],
1480+
})
1481+
.select(col("objs").struct.renameFields(["a", "b", "c"]));
1482+
const expected = pl.DataFrame({
1483+
objs: [
1484+
{ a: 1, b: 2.0, c: "abc" },
1485+
{ a: 10, b: 20.0, c: "def" },
1486+
],
1487+
});
1488+
expect(actual).toFrameStrictEqual(expected);
1489+
});
14721490
test("struct:withFields", () => {
14731491
const df = pl.DataFrame({
14741492
objs: [
@@ -1499,6 +1517,23 @@ describe("expr.str", () => {
14991517
);
15001518
expect(actual).toFrameStrictEqual(expected);
15011519
});
1520+
test("struct:jsonEncode", () => {
1521+
const actual = pl
1522+
.DataFrame({
1523+
a: [
1524+
{ a: [1, 2], b: [45] },
1525+
{ a: [9, 1, 3], b: null },
1526+
],
1527+
})
1528+
.withColumn(pl.col("a").struct.jsonEncode().alias("encoded"))
1529+
.toRecords();
1530+
1531+
const expected = [
1532+
{ a: { a: [1, 2], b: [45] }, encoded: '{"a":[1.0,2.0],"b":[45.0]}' },
1533+
{ a: { a: [9, 1, 3], b: null }, encoded: '{"a":[9.0,1.0,3.0],"b":null}' },
1534+
];
1535+
expect(actual).toEqual(expected);
1536+
});
15021537
test("expr.replace", () => {
15031538
const df = pl.DataFrame({ a: [1, 2, 2, 3], b: ["a", "b", "c", "d"] });
15041539
{

polars/lazy/expr/struct.ts

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,122 @@ export interface ExprStruct {
88
/**
99
* Access a field by name
1010
* @param name - name of the field
11+
* @example
12+
* pl.DataFrame({
13+
objs: [
14+
{ a: 1, b: 2.0, c: "abc" },
15+
{ a: 10, b: 20.0, c: "def" },
16+
],
17+
}).select(
18+
col("objs").struct.field("b"),
19+
col("objs").struct.field("c").as("last")
20+
);
21+
>>shape: (2, 2)
22+
┌──────┬──────┐
23+
│ b ┆ last │
24+
│ --- ┆ --- │
25+
│ f64 ┆ str │
26+
╞══════╪══════╡
27+
│ 2.0 ┆ abc │
28+
│ 20.0 ┆ def │
29+
└──────┴──────┘
1130
*/
1231
field(name: string): Expr;
1332
/**
1433
* Access a field by index (zero based index)
1534
* @param index - index of the field (starts at 0)
35+
*
36+
* @example
37+
* pl.DataFrame({
38+
objs: [
39+
{ a: 1, b: 2.0, c: "abc" },
40+
{ a: 10, b: 20.0, c: "def" },
41+
],
42+
}).select(
43+
col("objs").struct.nth(1),
44+
col("objs").struct.nth(2).as("last"),
45+
);
46+
>>shape: (2, 2)
47+
┌──────┬──────┐
48+
│ b ┆ last │
49+
│ --- ┆ --- │
50+
│ f64 ┆ str │
51+
╞══════╪══════╡
52+
│ 2.0 ┆ abc │
53+
│ 20.0 ┆ def │
54+
└──────┴──────┘
1655
*/
1756
nth(index: number): Expr;
1857
/**
1958
* Rename the fields of a struct
2059
* @param names - new names of the fields
60+
*
61+
* @example
62+
* pl.DataFrame({
63+
objs: [
64+
{ a: 1, b: 2.0, c: "abc" },
65+
{ a: 10, b: 20.0, c: "def" },
66+
]}).select(col("objs").struct.renameFields(["a", "b", "c"]));
67+
>>shape: (2, 1)
68+
┌───────────────────┐
69+
│ objs │
70+
│ --- │
71+
│ struct[3] │
72+
╞═══════════════════╡
73+
│ {1.0,2.0,"abc"} │
74+
│ {10.0,20.0,"def"} │
75+
└───────────────────┘
2176
*/
2277
renameFields(names: string[]): Expr;
2378
/**
2479
* Add/replace fields in a struct
2580
* @param fields - array of expressions for new fields
81+
*
82+
* @example
83+
* pl.DataFrame({
84+
objs: [
85+
{ a: 1, b: 2.0, c: "abc" },
86+
{ a: 10, b: 20.0, c: "def" },
87+
],
88+
more: ["text1", "text2"],
89+
final: [100, null],
90+
}).select(
91+
col("objs").struct.withFields([
92+
pl.lit(null).alias("d"),
93+
pl.lit("text").alias("e"),
94+
]),
95+
col("objs")
96+
.struct.withFields([col("more"), col("final")])
97+
.alias("new"),
98+
);
99+
shape: (2, 2)
100+
┌───────────────────────────────┬────────────────────────────────┐
101+
│ objs ┆ new │
102+
│ --- ┆ --- │
103+
│ struct[5] ┆ struct[5] │
104+
╞═══════════════════════════════╪════════════════════════════════╡
105+
│ {1.0,2.0,"abc",null,"text"} ┆ {1.0,2.0,"abc","text1",100.0} │
106+
│ {10.0,20.0,"def",null,"text"} ┆ {10.0,20.0,"def","text2",null} │
107+
└───────────────────────────────┴────────────────────────────────┘
26108
*/
27109
withFields(fields: Expr[]): Expr;
110+
/**
111+
* Convert this struct to a string column with json values.
112+
*
113+
* @example
114+
* pl.DataFrame( {"a": [{"a": [1, 2], "b": [45]}, {"a": [9, 1, 3], "b": null}]}
115+
).withColumn(pl.col("a").struct.jsonEncode().alias("encoded"))
116+
shape: (2, 2)
117+
┌──────────────────┬────────────────────────┐
118+
│ a ┆ encoded │
119+
│ --- ┆ --- │
120+
│ struct[2] ┆ str │
121+
╞══════════════════╪════════════════════════╡
122+
│ {[1, 2],[45]} ┆ {"a":[1,2],"b":[45]} │
123+
│ {[9, 1, 3],null} ┆ {"a":[9,1,3],"b":null} │
124+
└──────────────────┴────────────────────────┘
125+
*/
126+
jsonEncode(): Expr;
28127
}
29128

30129
export const ExprStructFunctions = (_expr: any): ExprStruct => {
@@ -42,5 +141,8 @@ export const ExprStructFunctions = (_expr: any): ExprStruct => {
42141
fields = selectionToExprList(fields, false);
43142
return _Expr(_expr.structWithFields(fields));
44143
},
144+
jsonEncode() {
145+
return _Expr(_expr.structJsonEncode());
146+
},
45147
};
46148
};

src/lazy/dsl.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,10 @@ impl JsExpr {
15351535
self.inner.clone().struct_().field_by_name(&name).into()
15361536
}
15371537
#[napi(catch_unwind)]
1538+
pub fn struct_json_encode(&self) -> JsExpr {
1539+
self.inner.clone().struct_().json_encode().into()
1540+
}
1541+
#[napi(catch_unwind)]
15381542
pub fn struct_rename_fields(&self, names: Vec<String>) -> JsExpr {
15391543
self.inner.clone().struct_().rename_fields(names).into()
15401544
}

0 commit comments

Comments
 (0)