|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | + <meta charset="UTF-8" /> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 6 | + <title>tsb — insertColumn / popColumn</title> |
| 7 | + <style> |
| 8 | + body { font-family: system-ui, sans-serif; max-width: 860px; margin: 2rem auto; padding: 0 1rem; line-height: 1.6; color: #1a1a1a; } |
| 9 | + h1 { color: #0066cc; } |
| 10 | + h2 { color: #333; border-bottom: 1px solid #eee; padding-bottom: 0.3em; } |
| 11 | + pre { background: #f6f8fa; border-radius: 6px; padding: 1rem; overflow-x: auto; font-size: 0.9em; } |
| 12 | + code { font-family: 'Fira Code', 'Cascadia Code', monospace; } |
| 13 | + .note { background: #fffbea; border-left: 4px solid #f5a623; padding: 0.7rem 1rem; border-radius: 0 6px 6px 0; margin: 1rem 0; } |
| 14 | + table { border-collapse: collapse; width: 100%; margin: 1rem 0; } |
| 15 | + th, td { border: 1px solid #ddd; padding: 0.5rem 0.75rem; text-align: left; } |
| 16 | + th { background: #f0f4f8; } |
| 17 | + a { color: #0066cc; } |
| 18 | + </style> |
| 19 | +</head> |
| 20 | +<body> |
| 21 | + <p><a href="index.html">← tsb playground</a></p> |
| 22 | + |
| 23 | + <h1><code>insertColumn</code> / <code>popColumn</code></h1> |
| 24 | + <p> |
| 25 | + Column insertion and removal for DataFrames — mirrors |
| 26 | + <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.insert.html" target="_blank"> |
| 27 | + <code>pandas.DataFrame.insert()</code></a> and |
| 28 | + <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.pop.html" target="_blank"> |
| 29 | + <code>pandas.DataFrame.pop()</code></a>. |
| 30 | + </p> |
| 31 | + <p> |
| 32 | + Because tsb DataFrames are <strong>immutable</strong>, both functions return a new DataFrame |
| 33 | + rather than mutating the original. <code>popColumn</code> returns both the extracted |
| 34 | + <code>Series</code> and the resulting DataFrame. |
| 35 | + </p> |
| 36 | + |
| 37 | + <h2>API summary</h2> |
| 38 | + <table> |
| 39 | + <thead><tr><th>Function</th><th>Pandas equivalent</th><th>Description</th></tr></thead> |
| 40 | + <tbody> |
| 41 | + <tr> |
| 42 | + <td><code>insertColumn(df, loc, col, values)</code></td> |
| 43 | + <td><code>df.insert(loc, col, value)</code></td> |
| 44 | + <td>Insert a new column at integer position <code>loc</code></td> |
| 45 | + </tr> |
| 46 | + <tr> |
| 47 | + <td><code>popColumn(df, col)</code></td> |
| 48 | + <td><code>df.pop(col)</code></td> |
| 49 | + <td>Remove a column; returns <code>{ series, df }</code></td> |
| 50 | + </tr> |
| 51 | + <tr> |
| 52 | + <td><code>reorderColumns(df, order)</code></td> |
| 53 | + <td><code>df[order]</code></td> |
| 54 | + <td>Reorder (and optionally subset) columns</td> |
| 55 | + </tr> |
| 56 | + <tr> |
| 57 | + <td><code>moveColumn(df, col, newLoc)</code></td> |
| 58 | + <td>—</td> |
| 59 | + <td>Move an existing column to a new integer position</td> |
| 60 | + </tr> |
| 61 | + </tbody> |
| 62 | + </table> |
| 63 | + |
| 64 | + <h2>Example 1 — <code>insertColumn</code></h2> |
| 65 | + <pre><code>import { DataFrame, insertColumn } from "tsb"; |
| 66 | + |
| 67 | +const df = DataFrame.fromColumns({ |
| 68 | + name: ["Alice", "Bob", "Carol"], |
| 69 | + age: [30, 25, 35], |
| 70 | +}); |
| 71 | +// columns: ["name", "age"] |
| 72 | + |
| 73 | +// Insert "city" between "name" and "age" |
| 74 | +const df2 = insertColumn(df, 1, "city", ["NY", "LA", "SF"]); |
| 75 | +// df2.columns.values → ["name", "city", "age"] |
| 76 | +// df2.col("city").values → ["NY", "LA", "SF"] |
| 77 | + |
| 78 | +// Original is unchanged |
| 79 | +// df.columns.values → ["name", "age"] |
| 80 | +</code></pre> |
| 81 | + |
| 82 | + <h2>Example 2 — Insert with a Series</h2> |
| 83 | + <pre><code>import { DataFrame, Series, insertColumn } from "tsb"; |
| 84 | + |
| 85 | +const df = DataFrame.fromColumns({ a: [1, 2, 3], b: [4, 5, 6] }); |
| 86 | +const salary = new Series({ data: [100_000, 90_000, 120_000], name: "salary" }); |
| 87 | + |
| 88 | +const df2 = insertColumn(df, 0, "salary", salary); |
| 89 | +// df2.columns.values → ["salary", "a", "b"] |
| 90 | +</code></pre> |
| 91 | + |
| 92 | + <h2>Example 3 — <code>popColumn</code></h2> |
| 93 | + <pre><code>import { DataFrame, popColumn } from "tsb"; |
| 94 | + |
| 95 | +const df = DataFrame.fromColumns({ |
| 96 | + id: [1, 2, 3], |
| 97 | + name: ["Alice", "Bob", "Carol"], |
| 98 | + age: [30, 25, 35], |
| 99 | +}); |
| 100 | + |
| 101 | +// Remove "age" and keep the Series |
| 102 | +const { series: ageSeries, df: df2 } = popColumn(df, "age"); |
| 103 | +// ageSeries.values → [30, 25, 35] |
| 104 | +// df2.columns.values → ["id", "name"] |
| 105 | +// df.columns.values → ["id", "name", "age"] ← original unchanged |
| 106 | +</code></pre> |
| 107 | + |
| 108 | + <h2>Example 4 — <code>reorderColumns</code></h2> |
| 109 | + <pre><code>import { DataFrame, reorderColumns } from "tsb"; |
| 110 | + |
| 111 | +const df = DataFrame.fromColumns({ a: [1], b: [2], c: [3], d: [4] }); |
| 112 | + |
| 113 | +// Reverse the column order |
| 114 | +const df2 = reorderColumns(df, ["d", "c", "b", "a"]); |
| 115 | +// df2.columns.values → ["d", "c", "b", "a"] |
| 116 | + |
| 117 | +// Select a subset (drops columns not listed) |
| 118 | +const df3 = reorderColumns(df, ["a", "c"]); |
| 119 | +// df3.columns.values → ["a", "c"] (b and d are dropped) |
| 120 | +</code></pre> |
| 121 | + |
| 122 | + <h2>Example 5 — <code>moveColumn</code></h2> |
| 123 | + <pre><code>import { DataFrame, moveColumn } from "tsb"; |
| 124 | + |
| 125 | +const df = DataFrame.fromColumns({ |
| 126 | + year: [2020, 2021, 2022], |
| 127 | + value: [10, 20, 30], |
| 128 | + label: ["a", "b", "c"], |
| 129 | +}); |
| 130 | +// columns: ["year", "value", "label"] |
| 131 | + |
| 132 | +// Move "label" to the front |
| 133 | +const df2 = moveColumn(df, "label", 0); |
| 134 | +// df2.columns.values → ["label", "year", "value"] |
| 135 | +</code></pre> |
| 136 | + |
| 137 | + <h2>Error cases</h2> |
| 138 | + <pre><code>// Duplicate column name (default: not allowed) |
| 139 | +insertColumn(df, 1, "a", [1, 2, 3]); |
| 140 | +// → RangeError: Column "a" already exists. Use allowDuplicates=true to permit... |
| 141 | + |
| 142 | +// Out-of-range loc |
| 143 | +insertColumn(df, 99, "x", [1, 2, 3]); |
| 144 | +// → RangeError: loc=99 is out of range [0, 2]. |
| 145 | + |
| 146 | +// Wrong number of values |
| 147 | +insertColumn(df, 0, "x", [1]); // df has 3 rows |
| 148 | +// → RangeError: values length 1 does not match DataFrame row count 3. |
| 149 | + |
| 150 | +// Column not found |
| 151 | +popColumn(df, "missing"); |
| 152 | +// → RangeError: Column "missing" not found in DataFrame. |
| 153 | +</code></pre> |
| 154 | + |
| 155 | + <div class="note"> |
| 156 | + <strong>Immutability:</strong> Like all tsb DataFrame operations, these functions never |
| 157 | + mutate the original DataFrame. Always assign the return value to a new variable. |
| 158 | + </div> |
| 159 | + |
| 160 | + <h2>pandas equivalence table</h2> |
| 161 | + <table> |
| 162 | + <thead> |
| 163 | + <tr><th>pandas</th><th>tsb</th></tr> |
| 164 | + </thead> |
| 165 | + <tbody> |
| 166 | + <tr><td><code>df.insert(1, "x", [1,2,3])</code> *(mutates)*</td><td><code>insertColumn(df, 1, "x", [1,2,3])</code></td></tr> |
| 167 | + <tr><td><code>series = df.pop("col")</code> *(mutates)*</td><td><code>const { series, df: df2 } = popColumn(df, "col")</code></td></tr> |
| 168 | + <tr><td><code>df[["c","a","b"]]</code></td><td><code>reorderColumns(df, ["c","a","b"])</code></td></tr> |
| 169 | + </tbody> |
| 170 | + </table> |
| 171 | +</body> |
| 172 | +</html> |
0 commit comments