 # Advice on a cleaner way to control the sort direction and filter inside a pipeline

I have several calculated values, for which I would like to extract
the "most interesting groups". Depending on the value, that will either be
the largest values, or the smallest of the ending values. To do this I
sort (by group) the data frame using the chosen column, and use a
function to control the sort direction. Then, similarly, I use a function
to select the top few groups.

In the real app I have a large table of counties with various measures (new
cases, doubling time, etc) for Covid as functions of date. I want to extract
the current 5 worst counties for new cases, doubling time, etc.

This all feels cumbersome and has proven to also be error-prone. Note
that this lives in a shiny app. Trying to debug a function being called
in a pipe inside shiny is pretty painful.

Is there a better pattern for being able to alter the direction of the
sort based on the value of a variable?

``````
library(tidyverse)

#########   set up reprex
ascending <- c("a", "b")

df <-  tribble(~names, ~a, ~b, ~c, ~d,
"A",  1,  2,  3,  4,
"B",  5,  6,  7,  8,
"C",  9, 10, 11, 12,
"A",  9, 10, 11, 12,
"B",  1,  2,  3,  4,
"C",  5,  6,  7,  8,
"A", 13, 14, 15, 16,
"B",  9, 10, 11, 12,
"C", 13, 14, 15, 16)

chosen_column <- c("a","c")

for (i in 1:2) {# test both sorts
########   Following is the bit that seems awkward

asc <- chosen_column[i] %in% ascending

do_sort <- function(df, asc) {
if (asc){
dplyr::arrange(df, Mselect)
} else {
dplyr::arrange(df, desc(Mselect))
}
}
do_filter <- function(df, asc) {
if (asc){
dplyr::filter(df, Mselect<=(unique(Mselect)))
} else {
dplyr::filter(df, Mselect>=(unique(Mselect)))
}
}

foo <- df %>%
group_by(names) %>%
# Store last value by group for sorting and selection
mutate(Mselect=last(!!as.name(chosen_column[i]))) %>%
ungroup() %>%
#  sort chosen column in proper direction
do_sort(asc) %>%
#  extract top few values
do_filter(asc) %>%
select(-Mselect)

print(foo)
}

``````

You can apply a multiplier to your `Mselect` variable to be either positive or negative depending on your `asc` variable. This produces the same results as above and is much briefer.

``````for (i in 1:2) {

asc <- chosen_column[i] %in% ascending
sort_direction <- 2*asc-1

foo2 <- df %>%
group_by(names) %>%
mutate(Mselect=sort_direction*last(!!as.name(chosen_column[i]))) %>%
ungroup() %>%
arrange(Mselect) %>%
filter(Mselect <= Mselect) %>%
select(-Mselect)

print(foo2)

}
``````

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

Ahhh yes, Clever. Thank you!