Skip to content

Commit

Permalink
perf(rename): avoid unnecessary rewrites and dereferencing in rename (
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcloud authored Jul 22, 2024
1 parent 27e30c9 commit e56489e
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 23 deletions.
39 changes: 16 additions & 23 deletions ibis/expr/types/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2359,22 +2359,13 @@ def rename(
# A mapping from old_name -> renamed expr
renamed = {}

if substitutions:
for new_name, old_name in substitutions.items():
col = self[old_name]
if old_name not in renamed:
renamed[old_name] = col.name(new_name)
else:
raise ValueError(
"duplicate new names passed for renaming {old_name!r}"
)

if method is None:

def rename(c):
return None
for new_name, old_name in substitutions.items():
if old_name not in renamed:
renamed[old_name] = (new_name, self[old_name].op())
else:
raise ValueError("duplicate new names passed for renaming {old_name!r}")

elif isinstance(method, str) and method in {"snake_case", "ALL_CAPS"}:
if isinstance(method, str) and method in {"snake_case", "ALL_CAPS"}:

def rename(c):
c = c.strip()
Expand Down Expand Up @@ -2412,17 +2403,19 @@ def rename(name):
else:
rename = method

exprs = []
exprs = {}
fields = self.op().fields
for c in self.columns:
if c in renamed:
expr = renamed[c]
if (new_name_op := renamed.get(c)) is not None:
new_name, op = new_name_op
else:
expr = self[c]
if (name := rename(c)) is not None:
expr = expr.name(name)
exprs.append(expr)
op = fields[c]
if rename is None or (new_name := rename(c)) is None:
new_name = c

exprs[new_name] = op

return self.select(exprs)
return ops.Project(self, exprs).to_expr()

def drop(self, *fields: str | Selector) -> Table:
"""Remove fields from a table.
Expand Down
27 changes: 27 additions & 0 deletions ibis/tests/benchmarks/test_benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,33 @@ def test_wide_drop_compile(benchmark, wide_table, cols_to_drop):
)


@pytest.mark.parametrize(
"method",
[
"snake_case",
"ALL_CAPS",
lambda x: f"t_{x}",
"t_{name}",
lambda x: x,
"{name}",
{"b0": "a0"},
],
ids=[
"snake_case",
"ALL_CAPS",
"function",
"format_string",
"no_op_function",
"no_op_string",
"mapping",
],
)
@pytest.mark.parametrize("cols", [1_000, 10_000])
def test_wide_rename(benchmark, method, cols):
t = ibis.table(name="t", schema={f"a{i}": "int" for i in range(cols)})
benchmark(t.rename, method)


def test_duckdb_timestamp_conversion(benchmark):
pytest.importorskip("duckdb")

Expand Down

0 comments on commit e56489e

Please sign in to comment.