Reputation: 77
I have a loop, where in the different iterations I want to sort the dataframe using different column lists. I can do this sorting when I hardcode the sorting variables. However I want to pass the column names using variable list. I could not find a way of doing this.
DT <-data.frame(avar = c(1,4,3,1), bvar = c("a","f","s","b"), cvar = c(3,4,5,2))
sort1 <-c("avar", "cvar")
sort2 <-c("avar", "bvar")
sorting <-list(sort1,sort2)
DT2<-list()
for (i in 1:2) {
sorter<- sorting[[i]]
#THE FOLLOWING SOLUTION WORKS!!!
DT2[[i]] <- DT[do.call(order,DT[as.character(sorting[[i]])]),]
}
What I mean by sorting by c("avar", "cvar") is that the data is to be sorted by avar first, and (if there are two values of avar that are the same) then by cvar. In other words, the output of sorting by that vector should be only one sorted dataframe (not a list). Same thing about sorting by c("avar", "bvar"). Above "ps1" stands for one of the proposed solutions. It gives me DT2[[1]] that is a list of two dataframes. that is not what I need. DT2 should be a list of two dataframes. DT2[[1]] should be one dataframe.
I want to also stress that I do need this sorting to happen through a loop, not through passing the list ("sorting") to the command. In other words, first iteration should sort the database by first item of the sorting list, which is the vector "sorter" in my code. In real application, the data in different iterations is not the same dataset.
After the first loop, DT2[[1]] should be sorted as follows:
avar bvar cvar
1 b 2
1 a 3
3 s 5
4 f 4
after the second loop DT2[[2]] should be sorted as :
avar bvar cvar
1 a 3
1 b 2
3 s 5
4 f 4
In real life I may also have a different number of sorting columns in different iteration.
Regarding solutions proposed that use "map" function: I have some geospacial packages loaded (mapproj, fiftystater, geofacet), so the "map" function does not work as suggested unless I unload those packages. Is there a way to qualify to use native "map" function rather than geospacial map function?
Thank you for your help!
Upvotes: 0
Views: 547
Reputation: 77
The following solution works for me! Other proposed solutions I tried failed to sort by two variables in a given vector simultaneously.
DT <-data.frame(avar = c(1,4,3,1), bvar = c("a","f","s","b"), cvar = c(3,4,5,2))
sort1 <-c("avar", "cvar")
sort2 <-c("avar", "bvar")
sorting <-list(sort1,sort2)
DT2<-list()
for (i in 1:2) {
#THE FOLLOWING SOLUTION WORKS!!!
DT2[[i]] <- DT[do.call(order,DT[as.character(sorting[[i]])]),]
}
Upvotes: 0
Reputation: 886938
Here is a method with setorder
from data.table
library(data.table)
Map(setorderv, replicate(2, copy(DT), simplify = FALSE), sorting)
#[[1]]
# avar bvar cvar
#4 1 b 2
#1 1 a 3
#3 3 s 5
#2 4 f 4
#[[2]]
# avar bvar cvar
#1 1 a 3
#4 1 b 2
#3 3 s 5
#2 4 f 4
Or use arrange_at
from dplyr
(without using the evaluation way)
library(tidyverse)
map(sorting, ~ DT %>%
arrange_at(.x))
#[[1]]
# avar bvar cvar
#1 1 b 2
#2 1 a 3
#3 3 s 5
#4 4 f 4
#[[2]]
# avar bvar cvar
#1 1 a 3
#2 1 b 2
#3 3 s 5
#4 4 f 4
Upvotes: 0
Reputation: 50668
A dplyr
+purrr
solution
library(purrr)
library(dplyr)
map(sorting, ~arrange(DT, !!!syms(.x)))
#[[1]]
# avar bvar cvar
#1 1 b 2
#2 1 a 3
#3 3 s 5
#4 4 f 4
#
#[[2]]
# avar bvar cvar
#1 1 a 3
#2 1 b 2
#3 3 s 5
#4 4 f 4
Upvotes: 1
Reputation: 388807
Using base R we can apply order
on selected columns in sorting
using do.call
. We use lapply
to get list of dataframes
lapply(sorting, function(x) DT[do.call(order, DT[x]), ])
#[[1]]
# avar bvar cvar
#4 1 b 2
#1 1 a 3
#3 3 s 5
#2 4 f 4
#[[2]]
# avar bvar cvar
#1 1 a 3
#4 1 b 2
#3 3 s 5
#2 4 f 4
Upvotes: 1