Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow permutaion of names in rename! #1974

Merged
merged 8 commits into from
Oct 14, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/abstractdataframe/abstractdataframe.jl
Original file line number Diff line number Diff line change
Expand Up @@ -150,21 +150,21 @@ rename(f::Function, df::AbstractDataFrame)

* `::AbstractDataFrame` : the updated result

New names are processed sequentially. A new name must not already exist in the `DataFrame`
at the moment an attempt to rename a column is performed.
Each name is changed at most once. Permutation of names is allowed.

**Examples**

```julia
df = DataFrame(i = 1:10, x = rand(10), y = rand(["a", "b", "c"], 10))
rename(df, :i => :A, :x => :X)
rename(df, :x => :y, :y => :x)
rename(df, [:i => :A, :x => :X])
rename(df, Dict(:i => :A, :x => :X))
rename(x -> Symbol(uppercase(string(x))), df)
rename(df) do x
Symbol(uppercase(string(x)))
end
rename!(df, Dict(:i =>: A, :x => :X))
rename!(df, Dict(:i => :A, :x => :X))
```

"""
Expand Down
31 changes: 29 additions & 2 deletions src/other/index.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,41 @@ function names!(x::Index, nms::Vector{Symbol}; makeunique::Bool=false)
end

function rename!(x::Index, nms)
xbackup = copy(x)
processedfrom = Set{Symbol}()
processedto = Set{Symbol}()
toholder = Dict{Symbol,Int}()
for (from, to) in nms
if from ∈ processedfrom
merge!(empty!(x.lookup), xbackup.lookup)
innerlee marked this conversation as resolved.
Show resolved Hide resolved
x.names .= xbackup.names
throw(ArgumentError("Tried renaming $from multiple times."))
end
if to ∈ processedto
merge!(empty!(x.lookup), xbackup.lookup)
x.names .= xbackup.names
throw(ArgumentError("Tried renaming to $to multiple times."))
end
push!(processedfrom, from)
push!(processedto, to)
from == to && continue # No change, nothing to do
if !haskey(xbackup, from)
merge!(empty!(x.lookup), xbackup.lookup)
x.names .= xbackup.names
throw(ArgumentError("Tried renaming $from to $to, when $from does not exist in the Index."))
end
if haskey(x, to)
error("Tried renaming $from to $to, when $to already exists in the Index.")
toholder[to] = x.lookup[to]
end
x.lookup[to] = col = pop!(x.lookup, from)
col = haskey(toholder, from) ? pop!(toholder, from) : pop!(x.lookup, from)
x.lookup[to] = col
x.names[col] = to
end
if !isempty(toholder)
merge!(empty!(x.lookup), xbackup.lookup)
x.names .= xbackup.names
throw(ArgumentError("Tried renaming to $(first(keys(toholder))), when it already exists in the Index."))
end
return x
end

Expand Down
27 changes: 27 additions & 0 deletions test/dataframe.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,33 @@ end
@test names(df) == [:A_4, :B_4]
@test rename!(x->Symbol(lowercase(string(x))), df) === df
@test names(df) == [:a_4, :b_4]

df = DataFrame(A = 1:3, B = 'A':'C', C = [:x, :y, :z])
@test rename!(df, :A => :B, :B => :A) === df
@test names(df) == [:B, :A, :C]
@test rename!(df, :A => :B, :B => :A, :C => :D) === df
@test names(df) == [:A, :B, :D]
@test rename!(df, :A => :B, :B => :C, :D => :A) === df
@test names(df) == [:B, :C, :A]
@test rename!(df, :A => :C, :B => :A, :C => :B) === df
@test names(df) == [:A, :B, :C]
@test rename!(df, :A => :A, :B => :B, :C => :C) === df
@test names(df) == [:A, :B, :C]

@test_throws ArgumentError rename!(df, :X => :Y)
@test names(df) == [:A, :B, :C]
innerlee marked this conversation as resolved.
Show resolved Hide resolved
@test_throws ArgumentError rename!(df, :A => :X, :X => :Y)
@test names(df) == [:A, :B, :C]
@test_throws ArgumentError rename!(df, :A => :B)
@test names(df) == [:A, :B, :C]
@test_throws ArgumentError rename!(df, :A => :X, :A => :X)
@test names(df) == [:A, :B, :C]
@test_throws ArgumentError rename!(df, :A => :X, :B => :X)
@test names(df) == [:A, :B, :C]
@test_throws ArgumentError rename!(df, :A => :B, :B => :A, :C => :B)
@test names(df) == [:A, :B, :C]
@test_throws ArgumentError rename!(df, :A => :B, :B => :A, :A => :X)
@test names(df) == [:A, :B, :C]
end

@testset "size" begin
Expand Down