# DataFrame inplace change columns order

**URL:** <https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971>\
**Category:** Data\
**Created:** [February 21, 2023, 5:26pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971 "2023-02-21T17:26:48Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![PharmCat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pharmcat/32/6953_2.png) [@PharmCat](https://discourse.julialang.org/u/PharmCat)\
**Post date:** [February 21, 2023, 5:26pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/1 "2023-02-21T17:26:48Z")

</div>

Is it possible to change index of two columns by each other in place?

I know than I can use something `df[!, [:b, :a]]`, but I can have many columns… so is any efficient way to change columns with function like:

```julia
function colreorder!(df, :a => :b)
    # Something
end

```

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [February 21, 2023, 5:31pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/2 "2023-02-21T17:31:24Z")

</div>

`select!` might help?

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [February 21, 2023, 5:43pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/3 "2023-02-21T17:43:20Z")

</div>

I think this is a good need and something I’ve often wanted in DataFrames.jl. For example, if the following methods existed, they would maybe solve your problem:

```julia
julia> movecolumn(df, name::Union{Symbol, String}, i::Int) = begin end;

julia> movecolumn(df, name::Union{Symbol, String}; after::Union{Symbol, String, Int}, before::Union{Symbol, String, Int} = nothing) = begin end;

```

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [February 21, 2023, 5:52pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/5 "2023-02-21T17:52:29Z")

</div>

This can be done as follows:

```julia
julia> using Permutations

julia> df = DataFrame(x=1, a=2, y=3, b=4, z=5)
1×5 DataFrame
 Row │ x a y b z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 2 3 4 5

julia> select(df, collect(Transposition(ncol(df), columnindex(df, :a), columnindex(df, :b))))
1×5 DataFrame
 Row │ x b y a z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 4 3 2 5

```

Clearly this is not super convenient and requires extra package.

In fact, we have an internal implementation of efficient permutation handling using cycle notation, it is just not exposed.

Could you open an issue with a description of a functionality that would be requested? (in particular I am not sure if what @pdeffebach is needed or rather a support for specifying cycles in a general permutation?)

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [February 21, 2023, 5:53pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/6 "2023-02-21T17:53:34Z")

</div>

The other way to do it is:

```julia
julia> using Permutations

julia> df = DataFrame(x=1, a=2, y=3, b=4, z=5)
1×5 DataFrame
 Row │ x a y b z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 2 3 4 5

julia> select(df, collect(Transposition(ncol(df), columnindex(df, :a), columnindex(df, :b))))
1×5 DataFrame
 Row │ x b y a z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 4 3 2 5

```

it is better but still boilerplate code is needed.

---

<div class="post-metadata">

**Author:** ![PharmCat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pharmcat/32/6953_2.png) [@PharmCat](https://discourse.julialang.org/u/PharmCat)\
**Post date:** [February 21, 2023, 5:59pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/7 "2023-02-21T17:59:28Z")

</div>

It work in situations like this:

```julia
select!(df, 2,1,:)

```

now I make it this way:

```julia
function swap!(df, pair::Pair{Int, Int})
    range = 1:size(df,2)
    if !(pair[1] in range) || !(pair[2] in range) error("Inds not in range") end
    inds = collect(1:size(df,2))
    @inbounds inds[pair[1]], inds[pair[2]] = inds[pair[2]], inds[pair[1]]
    select!(df, inds)
end

```

---

<div class="post-metadata">

**Author:** ![PharmCat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pharmcat/32/6953_2.png) [@PharmCat](https://discourse.julialang.org/u/PharmCat)\
**Post date:** [February 21, 2023, 6:05pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/8 "2023-02-21T18:05:19Z")

</div>

Thank you! In this case Permutations needs and this is very unintuitive.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [February 21, 2023, 6:46pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/9 "2023-02-21T18:46:55Z")

</div>

Ah - I pasted wrong output in the second solution:

```julia
julia> df = DataFrame(x=1, a=2, y=3, b=4, z=5)
1×5 DataFrame
 Row │ x a y b z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 2 3 4 5

julia> rename!(transform(df, :a => :b, :b => :a), :a => :b, :b => :a)
1×5 DataFrame
 Row │ x b y a z
     │ Int64 Int64 Int64 Int64 Int64
─────┼───────────────────────────────────
   1 │ 1 4 3 2 5

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 22, 2023, 4:01pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/10 "2023-02-22T16:01:53Z")

</div>

if the data types of the involved columns are compatible, a schema of this type should be used

```julia
function dfswapcols(df, col1, col2)
    
    df[:,col1], df[:,col2] = df[:,col2], df[:,col1]
    rename!(df, names(df)[col1]=>names(df)[col2], names(df)[col2]=>names(df)[col1])

end

```

---

<div class="post-metadata">

**Author:** ![dnb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnb/32/47121_2.png) [@dnb](https://discourse.julialang.org/u/dnb)\
**Post date:** [February 22, 2023, 7:57pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/11 "2023-02-22T19:57:05Z")

</div>

Wouldn’t something like this work?

```julia

dfswapcols(df, c1::String, c2::String) = select!(df, replace(names(df), c1 => c2, c2 => c1))

dfswapcols(df, c1::Symbol, c2::Symbol) = dfswapcols(df, String(c1), String(c2))

dfswapcols(df, c1::Int64, c2::Int64) = select!(df, replace(collect(1:ncol(df)), c1 => c2, c2 => c1))

```

Credit rocco\_sprmnt21 for the function name

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 22, 2023, 8:21pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/12 "2023-02-22T20:21:22Z")

</div>

for example like this, if you have a dataframe with 5 columns and you want to swap 4 and 5 or permute in a more generic way (may be not in a random way)

```julia
select!(df, permute!(names(df), [1,2,3,5,4]))

using Random
select!(df, permute!(names(df), shuffle(1:5)))

```

---

<div class="post-metadata">

**Author:** ![dnb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnb/32/47121_2.png) [@dnb](https://discourse.julialang.org/u/dnb)\
**Post date:** [February 22, 2023, 8:47pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/13 "2023-02-22T20:47:21Z")

</div>

You probably don’t even need to permute! the names since select! accepts a vector of integers as an argument  
`select!(df, [1,2,3,5,4])` works as well

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 23, 2023, 10:31am UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/14 "2023-02-23T10:31:01Z")

</div>

I propose this way to get some clarification on a possible implementation (even if it doesn’t make sense to do it, for some reason).

```julia
nt=Tables.columntable(df)
perm=[3,2,4,5,1]
DataFrame(NamedTuple{Tuple(permute!(collect(keys(nt)),perm ))}(nt))

```

I would like to know if and how to use a generated function similar to what @aplavin did [here](https://discourse.julialang.org/t/sort-keys-of-namedtuple/94630)

```julia
@generated sortkeys(nt::NamedTuple{KS}) where {KS} =
    :( NamedTuple{$(Tuple(sort(collect(KS))))}(nt) )

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 24, 2023, 3:44pm UTC](https://discourse.julialang.org/t/dataframe-inplace-change-columns-order/94971/15 "2023-02-24T15:44:06Z")

</div>

I don’t want to offer this as a solution to the problem, but it’s just a snippet so I can ask a specific question.  
It would be possible and would make sense to implement a function of the requested type

```julia
function color order!(df, old_order .=> new_order)
     #Something
end

```

internally, along the following lines?

```julia

julia> using DataFrames

julia> m='A':'C'
'A':1:'C'

julia> sc=10:10:30
10:10:30

julia> lt=1:3
1:3

julia> df=DataFrame(;m,sc,lt)
3×3 DataFrame
 Row │ m sc lt    
     │ Char Int64 Int64
─────┼────────────────────
   1 │ A 10 1
   2 │ B 20 2
   3 │ C 30 3

julia> DataFrames.index(df).lookup[:m]=2
2

julia> DataFrames.index(df).lookup[:sc]=1
1

julia> DataFrames.index(df).names.=[:sc,:m,:lt]
3-element Vector{Symbol}:
 :sc
 :m
 :lt

julia> df
3×3 DataFrame
 Row │ sc m lt    
     │ Char Int64 Int64
─────┼────────────────────
   1 │ A 10 1
   2 │ B 20 2
   3 │ C 30 3

```
