Skip to content

Commit 6c6afde

Browse files
committed
Unify CTable indexing around t[...]
- Make CTable.getitem type-driven for rows, columns, and expressions - Return namedtuple-like rows for integer indexing - Keep slices, gathers, masks, and projections as CTable views - Add t["expr"] shorthand for boolean row filtering - Add where(..., columns=[...]) filtered projection - Add NumPy structured-array materialization via array() - Remove the legacy t.row[...] accessor - Update tests, docs, examples, and benches to the new API
1 parent 2dfeba8 commit 6c6afde

14 files changed

Lines changed: 305 additions & 186 deletions

bench/ctable/row_access.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# SPDX-License-Identifier: BSD-3-Clause
66
#######################################################################
77

8-
# Benchmark for measuring row[int] access (full row via _RowIndexer),
8+
# Benchmark for measuring row[int] access via CTable.__getitem__,
99
# testing access at different positions across the array.
1010

1111
from dataclasses import dataclass
@@ -54,7 +54,7 @@ class Row:
5454

5555
for idx in indices:
5656
t0 = time()
57-
row = ct.row[idx]
57+
row = ct[idx]
5858
t_access = time() - t0
5959
position = f"{idx / N * 100:.0f}% into array"
6060
print(f"{idx:<15,} {position:>12} {t_access:.6f}")

doc/reference/ctable.rst

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,35 @@ or use string expressions when that reads better::
153153

154154
t.where("amount > 100 and region == 'North'")
155155
t.where("not returned")
156+
t["not returned"]
156157

157-
The last two forms for negating a boolean column are equivalent: ``t.where(~t.returned)``
158-
and ``t.where("not returned")``.
158+
The last three forms for negating a boolean column are equivalent:
159+
``t.where(~t.returned)``, ``t.where("not returned")``, and
160+
``t["not returned"]``.
161+
162+
Indexing & projection
163+
~~~~~~~~~~~~~~~~~~~~~
164+
165+
CTable indexing is type-driven::
166+
167+
t["amount"] # column access
168+
t[3] # one row as a namedtuple-like object
169+
t[3:8] # row view
170+
t[[1, 4, 7]] # gathered-row view
171+
t[mask] # filtered row view
172+
t[["region", "amount"]] # projected column view
173+
174+
String keys first try exact column-name lookup. If the string is not a
175+
column name, it is interpreted as a boolean expression and behaves like
176+
:meth:`CTable.where`.
177+
178+
For explicit filtered projection, use::
179+
180+
t.where("amount > 100", columns=["region", "amount"])
181+
182+
When a NumPy structured array is needed, materialize explicitly::
183+
184+
np.asarray(t[:10])
159185

160186
.. autosummary::
161187

examples/ctable/basics.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# SPDX-License-Identifier: BSD-3-Clause
66
#######################################################################
77

8-
# CTable basics: creation, append, extend, head/tail, len.
8+
# CTable basics: creation, append, extend, row access, head/tail, len.
99

1010
from dataclasses import dataclass
1111

@@ -41,7 +41,8 @@ class Row:
4141
arr["price"] = np.linspace(10.0, 14.0, 5)
4242
arr["active"] = [True, False, True, False, True]
4343
t.extend(arr)
44-
print(f"After numpy extend: {len(t)} rows\n")
44+
print(f"After numpy extend: {len(t)} rows")
45+
print(f"Row 0 via t[0]: {t[0]}\n")
4546

4647
# -- display: head / tail / full table --------------------------------------
4748
print("head(3):")

examples/ctable/querying.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# SPDX-License-Identifier: BSD-3-Clause
66
#######################################################################
77

8-
# Querying: where() filters, select() column projection, and chaining.
8+
# Querying: expression indexing, where() filters, projection, and chaining.
99

1010
from dataclasses import dataclass
1111

@@ -40,7 +40,7 @@ class Sale:
4040
print(f"Sales > $200: {len(high_value)} rows")
4141
print(high_value)
4242

43-
not_returned = t.where("not returned")
43+
not_returned = t["not returned"]
4444
print(f"Not returned: {len(not_returned)} rows")
4545

4646
# -- chained filters (views are composable) ---------------------------------
@@ -49,12 +49,12 @@ class Sale:
4949
print(f"North region + amount > 100: {len(north_big)} rows")
5050
print(north_big)
5151

52-
# -- select(): column projection (no data copy) -----------------------------
53-
slim = t.select(["id", "amount"])
52+
# -- column projection via [] (no data copy) --------------------------------
53+
slim = t[["id", "amount"]]
5454
print("id + amount only:")
5555
print(slim)
5656

57-
# -- combined: select columns, then filter rows -----------------------------
58-
result = t.where("not returned").select(["region", "amount"])
57+
# -- combined filter + projection -------------------------------------------
58+
result = t.where("not returned", columns=["region", "amount"])
5959
print("Region + amount for non-returned sales:")
6060
print(result)

0 commit comments

Comments
 (0)