11"""
2- append!(df::DataFrame, df2::AbstractDataFrame; cols::Symbol=:setequal,
3- promote::Bool=(cols in [:union, :subset]))
4- append!(df::DataFrame, table; cols::Symbol=:setequal,
2+ append!(df::DataFrame, tables...; cols::Symbol=:setequal,
53 promote::Bool=(cols in [:union, :subset]))
64
7- Add the rows of `df2 ` to the end of `df`. If the second argument ` table` is not
8- an `AbstractDataFrame` then it is converted using `DataFrame(table,
9- copycols=false)` before being appended.
5+ Add the rows of tables passed as `tables ` to the end of `df`. If the table is not
6+ an `AbstractDataFrame` then it is converted using
7+ `DataFrame(table, copycols=false)` before being appended.
108
119The exact behavior of `append!` depends on the `cols` argument:
1210* If `cols == :setequal` (this is the default) then `df2` must contain exactly
@@ -78,18 +76,53 @@ julia> df1
7876 4 │ 4 4
7977 5 │ 5 5
8078 6 │ 6 6
79+
80+ julia> append!(df2, DataFrame(A=1), (; C=1:2), cols=:union)
81+ 6×3 DataFrame
82+ Row │ A B C
83+ │ Float64? Int64? Int64?
84+ ─────┼─────────────────────────────
85+ 1 │ 4.0 4 missing
86+ 2 │ 5.0 5 missing
87+ 3 │ 6.0 6 missing
88+ 4 │ 1.0 missing missing
89+ 5 │ missing missing 1
90+ 6 │ missing missing 2
8191```
8292"""
8393Base. append! (df1:: DataFrame , df2:: AbstractDataFrame ; cols:: Symbol = :setequal ,
8494 promote:: Bool = (cols in [:union , :subset ])) =
8595 _append_or_prepend! (df1, df2, cols= cols, promote= promote, atend= true )
8696
97+ function Base. append! (df:: DataFrame , table; cols:: Symbol = :setequal ,
98+ promote:: Bool = (cols in [:union , :subset ]))
99+ if table isa Dict && cols == :orderequal
100+ throw (ArgumentError (" passing `Dict` as `table` when `cols` is equal to " *
101+ " `:orderequal` is not allowed as it is unordered" ))
102+ end
103+ append! (df, DataFrame (table, copycols= false ), cols= cols, promote= promote)
104+ end
105+
106+ function Base. append! (df:: DataFrame , @nospecialize tables... ;
107+ cols:: Symbol = :setequal ,
108+ promote:: Bool = (cols in [:union , :subset ]))
109+ if ! (cols in (:orderequal , :setequal , :intersect , :subset , :union ))
110+ throw (ArgumentError (" `cols` keyword argument must be " *
111+ " :orderequal, :setequal, :intersect, :subset or :union)" ))
112+ end
113+
114+ return foldl ((df, table) -> append! (df, table, cols= cols, promote= promote),
115+ collect (Any, tables), init= df)
116+ end
117+
87118"""
88- prepend!(df::DataFrame, df2::AbstractDataFrame; cols::Symbol=:setequal,
89- promote::Bool=(cols in [:union, :subset]))
90- prepend!(df::DataFrame, table; cols::Symbol=:setequal,
119+ prepend!(df::DataFrame, tables...; cols::Symbol=:setequal,
91120 promote::Bool=(cols in [:union, :subset]))
92121
122+ Add the rows of tables passed as `tables` to the beginning of `df`. If the table is not
123+ an `AbstractDataFrame` then it is converted using
124+ `DataFrame(table, copycols=false)` before being appended.
125+
93126Add the rows of `df2` to the beginning of `df`. If the second argument `table`
94127is not an `AbstractDataFrame` then it is converted using `DataFrame(table,
95128copycols=false)` before being prepended.
@@ -164,12 +197,45 @@ julia> df1
164197 4 │ 1 1
165198 5 │ 2 2
166199 6 │ 3 3
200+
201+ julia> prepend!(df2, DataFrame(A=1), (; C=1:2), cols=:union)
202+ 6×3 DataFrame
203+ Row │ A B C
204+ │ Float64? Int64? Int64?
205+ ─────┼─────────────────────────────
206+ 1 │ 1.0 missing missing
207+ 2 │ missing missing 1
208+ 3 │ missing missing 2
209+ 4 │ 4.0 4 missing
210+ 5 │ 5.0 5 missing
211+ 6 │ 6.0 6 missing
167212```
168213"""
169214Base. prepend! (df1:: DataFrame , df2:: AbstractDataFrame ; cols:: Symbol = :setequal ,
170215 promote:: Bool = (cols in [:union , :subset ])) =
171216 _append_or_prepend! (df1, df2, cols= cols, promote= promote, atend= false )
172217
218+ function Base. prepend! (df:: DataFrame , table; cols:: Symbol = :setequal ,
219+ promote:: Bool = (cols in [:union , :subset ]))
220+ if table isa Dict && cols == :orderequal
221+ throw (ArgumentError (" passing `Dict` as `table` when `cols` is equal to " *
222+ " `:orderequal` is not allowed as it is unordered" ))
223+ end
224+ prepend! (df, DataFrame (table, copycols= false ), cols= cols, promote= promote)
225+ end
226+
227+ function Base. prepend! (df:: DataFrame , @nospecialize tables... ;
228+ cols:: Symbol = :setequal ,
229+ promote:: Bool = (cols in [:union , :subset ]))
230+ if ! (cols in (:orderequal , :setequal , :intersect , :subset , :union ))
231+ throw (ArgumentError (" `cols` keyword argument must be " *
232+ " :orderequal, :setequal, :intersect, :subset or :union)" ))
233+ end
234+
235+ return foldr ((table, df) -> prepend! (df, table, cols= cols, promote= promote),
236+ collect (Any, tables), init= df)
237+ end
238+
173239function _append_or_prepend! (df1:: DataFrame , df2:: AbstractDataFrame ; cols:: Symbol ,
174240 promote:: Bool , atend:: Bool )
175241 if ! (cols in (:orderequal , :setequal , :intersect , :subset , :union ))
@@ -355,6 +421,10 @@ following way:
355421 added to `df` (using `missing` for existing rows) and a `missing` value is
356422 pushed to columns missing in `row` that are present in `df`.
357423
424+ If `row` is not a `DataFrameRow`, `NamedTuple`, `AbstractDict`, or `Tables.AbstractRow`
425+ the `cols` keyword argument must be `:setequal` (the default),
426+ because such rows do not provide column name information.
427+
358428If `promote=true` and element type of a column present in `df` does not allow
359429the type of a pushed argument then a new column with a promoted element type
360430allowing it is freshly allocated and stored in `df`. If `promote=false` an error
@@ -371,12 +441,14 @@ $METADATA_FIXED
371441"""
372442
373443"""
374- push!(df::DataFrame, row::Union{Tuple, AbstractArray}; promote::Bool=false)
444+ push!(df::DataFrame, row::Union{Tuple, AbstractArray}...;
445+ cols::Symbol=:setequal, promote::Bool=false)
375446 push!(df::DataFrame, row::Union{DataFrameRow, NamedTuple, AbstractDict,
376- Tables.AbstractRow};
447+ Tables.AbstractRow}... ;
377448 cols::Symbol=:setequal, promote::Bool=(cols in [:union, :subset]))
378449
379450Add one row at the end of `df` in-place, taking the values from `row`.
451+ Several rows can be added by passing them as separate arguments.
380452
381453$INSERTION_COMMON
382454
@@ -452,18 +524,36 @@ julia> push!(df, NamedTuple(), cols=:subset)
452524 6 │ 11 12 missing
453525 7 │ 1.0 missing 1.0
454526 8 │ missing missing missing
527+
528+ julia> push!(DataFrame(a=1, b=2), (3, 4), (5, 6))
529+ 3×2 DataFrame
530+ Row │ a b
531+ │ Int64 Int64
532+ ─────┼──────────────
533+ 1 │ 1 2
534+ 2 │ 3 4
535+ 3 │ 5 6
455536```
456537"""
457- Base. push! (df:: DataFrame , row:: Any ; promote:: Bool = false ) =
458- _row_inserter! (df, - 1 , row, Val {:push} (), promote)
538+ function Base. push! (df:: DataFrame , row:: Any ;
539+ cols= :setequal , promote:: Bool = false )
540+ if cols != = :setequal
541+ throw (ArgumentError (" `cols` can only be `:setequal` when `row` is a `$(typeof (row)) ` " *
542+ " as this type does not provide column names" ))
543+ end
544+
545+ return _row_inserter! (df, - 1 , row, Val {:push} (), promote)
546+ end
459547
460548"""
461- pushfirst!(df::DataFrame, row::Union{Tuple, AbstractArray}; promote::Bool=false)
549+ pushfirst!(df::DataFrame, row::Union{Tuple, AbstractArray}...;
550+ cols::Symbol=:setequal, promote::Bool=false)
462551 pushfirst!(df::DataFrame, row::Union{DataFrameRow, NamedTuple, AbstractDict,
463- Tables.AbstractRow};
552+ Tables.AbstractRow}... ;
464553 cols::Symbol=:setequal, promote::Bool=(cols in [:union, :subset]))
465554
466555Add one row at the beginning of `df` in-place, taking the values from `row`.
556+ Several rows can be added by passing them as separate arguments.
467557
468558$INSERTION_COMMON
469559
@@ -539,13 +629,30 @@ julia> pushfirst!(df, NamedTuple(), cols=:subset)
539629 6 │ a 1 missing
540630 7 │ b 2 missing
541631 8 │ c 3 missing
632+
633+ julia> pushfirst!(DataFrame(a=1, b=2), (3, 4), (5, 6))
634+ 3×2 DataFrame
635+ Row │ a b
636+ │ Int64 Int64
637+ ─────┼──────────────
638+ 1 │ 3 4
639+ 2 │ 5 6
640+ 3 │ 1 2
542641```
543642"""
544- Base. pushfirst! (df:: DataFrame , row:: Any ; promote:: Bool = false ) =
545- _row_inserter! (df, - 1 , row, Val {:pushfirst} (), promote)
643+ function Base. pushfirst! (df:: DataFrame , row:: Any ;
644+ cols= :setequal , promote:: Bool = false )
645+ if cols != = :setequal
646+ throw (ArgumentError (" `cols` can only be `:setequal` when `row` is a `$(typeof (row)) ` " *
647+ " as this type does not provide column names" ))
648+ end
649+
650+ return _row_inserter! (df, - 1 , row, Val {:pushfirst} (), promote)
651+ end
546652
547653"""
548- insert!(df::DataFrame, index::Integer, row::Union{Tuple, AbstractArray}; promote::Bool=false)
654+ insert!(df::DataFrame, index::Integer, row::Union{Tuple, AbstractArray};
655+ cols::Symbol=:setequal, promote::Bool=false)
549656 insert!(df::DataFrame, index::Integer, row::Union{DataFrameRow, NamedTuple,
550657 AbstractDict, Tables.AbstractRow};
551658 cols::Symbol=:setequal, promote::Bool=(cols in [:union, :subset]))
@@ -629,7 +736,13 @@ julia> insert!(df, 3, NamedTuple(), cols=:subset)
629736 8 │ 1.0 missing 1.0
630737```
631738"""
632- function Base. insert! (df:: DataFrame , index:: Integer , row:: Any ; promote:: Bool = false )
739+ function Base. insert! (df:: DataFrame , index:: Integer , row:: Any ;
740+ cols= :setequal , promote:: Bool = false )
741+ if cols != = :setequal
742+ throw (ArgumentError (" `cols` can only be `:setequal` when `row` is a `$(typeof (row)) ` " *
743+ " as this type does not provide column names" ))
744+ end
745+
633746 index isa Bool && throw (ArgumentError (" invalid index: $index of type Bool" ))
634747 1 <= index <= nrow (df)+ 1 ||
635748 throw (ArgumentError (" invalid index: $index for data frame with $(nrow (df)) rows" ))
@@ -986,3 +1099,37 @@ function _row_inserter!(df::DataFrame, loc::Integer,
9861099 _drop_all_nonnote_metadata! (df)
9871100 return df
9881101end
1102+
1103+ function Base. push! (df:: DataFrame , @nospecialize rows... ;
1104+ cols:: Symbol = :setequal ,
1105+ promote:: Bool = (cols in [:union , :subset ]))
1106+ if ! (cols in (:orderequal , :setequal , :intersect , :subset , :union ))
1107+ throw (ArgumentError (" `cols` keyword argument must be " *
1108+ " :orderequal, :setequal, :intersect, :subset or :union)" ))
1109+ end
1110+ with_names_count = count (rows) do row
1111+ row isa Union{DataFrameRow,AbstractDict,NamedTuple,Tables. AbstractRow}
1112+ end
1113+ if 0 < with_names_count < length (rows)
1114+ throw (ArgumentError (" Mixing rows with column names and without column names " *
1115+ " in a single `push!` call is not allowed" ))
1116+ end
1117+ return foldl ((df, row) -> push! (df, row, cols= cols, promote= promote), rows, init= df)
1118+ end
1119+
1120+ function Base. pushfirst! (df:: DataFrame , @nospecialize rows... ;
1121+ cols:: Symbol = :setequal ,
1122+ promote:: Bool = (cols in [:union , :subset ]))
1123+ if ! (cols in (:orderequal , :setequal , :intersect , :subset , :union ))
1124+ throw (ArgumentError (" `cols` keyword argument must be " *
1125+ " :orderequal, :setequal, :intersect, :subset or :union)" ))
1126+ end
1127+ with_names_count = count (rows) do row
1128+ row isa Union{DataFrameRow,AbstractDict,NamedTuple,Tables. AbstractRow}
1129+ end
1130+ if 0 < with_names_count < length (rows)
1131+ throw (ArgumentError (" Mixing rows with column names and without column names " *
1132+ " in a single `push!` call is not allowed" ))
1133+ end
1134+ return foldr ((row, df) -> pushfirst! (df, row, cols= cols, promote= promote), rows, init= df)
1135+ end
0 commit comments