Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 7 additions & 1 deletion src/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4666,18 +4666,24 @@ materialize(v::Vector) = v
# A duplicate takes the smallest `name_k` not used by ANY
# name — original or already assigned — so `a,a,a_1` becomes `a,a_2,a_1`
# (renames never collide with an original that appears later).
#
# `taken` only grows, so every suffix below the last one assigned to a name is
# still taken: the search resumes there, which keeps N copies of one name linear.
function makeunique!(names::Vector{Symbol})
taken = Set(names)
length(taken) == length(names) && return names
seen = Set{Symbol}()
nextk = Dict{Symbol, Int}()
for i in eachindex(names)
nm = names[i]
if nm in seen
k = 1
k = get(nextk, nm, 1)
newnm = Symbol(nm, :_, k)
while newnm in taken
k += 1
newnm = Symbol(nm, :_, k)
end
nextk[nm] = k + 1
push!(taken, newnm)
names[i] = newnm
push!(seen, newnm)
Expand Down
11 changes: 11 additions & 0 deletions test/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,17 @@ end
@test_throws ArgumentError A.File(IOBuffer("a,b\nx,y\n1,2\n"); header=[3, 1])
end

@testset "duplicate column names" begin
@test Base.names(A.File(IOBuffer("a,a,a\n"))) == [:a, :a_1, :a_2]
@test Base.names(A.File(IOBuffer("a,a_1,a\n"))) == [:a, :a_1, :a_2]
@test Base.names(A.File(IOBuffer("a,a,a_1\n"))) == [:a, :a_2, :a_1]
# Each copy resumes the suffix search, so many copies of one name stay
# linear; a search that restarts at 1 for every copy allocates gigabytes.
n = 4_000
@test A.makeunique!(fill(:x, n)) == [:x; [Symbol(:x_, k) for k in 1:(n - 1)]]
@test (@allocated A.makeunique!(fill(:x, n))) < 100_000_000
end

@testset "row windowing and source modes (raw-row semantics)" begin
sourceparity("a,b\n1,2\n3,4\n5,6\n"; kw=(; limit=2))
sourceparity("a,b\n1,2\n3,4\n5,6\n"; kw=(; footerskip=2))
Expand Down
Loading