Search code examples
rdplyrdata-manipulation

base::ifelse() within dplyr::arrange() for conditional arrangement of grouped rows


I'm trying to order the rows of a data.frame conditional upon the value of another column.

Here's an example below:

library(magrittr)
library(dplyr)

df <- data.frame(grp = c(1,1,1,2,2,2), 
                 ori = c("f","f","f","r","r","r"),
                 ite = c("A","B","C","A","B","C"))

df

# #  grp ori ite
# 1   1   f   A
# 2   1   f   B
# 3   1   f   C
# 4   2   r   A
# 5   2   r   B
# 6   2   r   C

df %>%
  group_by(grp) %>%
  arrange(ifelse(ori == "f", ite, desc(ite)), .by_group = TRUE) %>%
  ungroup()

# # A tibble: 6 × 3
# # Groups:   grp [2]
#     grp ori   ite  
#   <dbl> <chr> <chr>
# 1     1 f     A    
# 2     1 f     B    
# 3     1 f     C    
# 4     2 r     A    
# 5     2 r     B    
# 6     2 r     C   

The expected output is:

# #  grp ori ite
# 1   1   f   A
# 2   1   f   B
# 3   1   f   C
# 4   2   r   C
# 5   2   r   B
# 6   2   r   A

I have a general idea of why it doesn't work: arrange() cannot look at things on a per-row basis, which is what the ifelse() is asking it to do.

Is there a better way of accomplishing this?


Solution

  • The idea to use ifelse(ori == "f", ite, desc(ite)) is basically good, unfortunately desc(ite) has a negative numeric vector as output, whereas the output of ite is a character vector.

    ifelse(df$ori == "f", df$ite, dplyr::desc(df$ite))
    #> [1] "A"  "B"  "C"  "-1" "-3" "-5"
    

    To bring the result of ite in reverse order using the same output as input we can write a function asc() which just does the opposite of desc():

    asc <- function(x) {
      xtfrm(x)
    }
    

    No we can use both inside ifelse():

    library(dplyr)
    
    df <- data.frame(grp = c(1,1,1,2,2,2), 
                     ori = c("f","f","f","r","r","r"),
                     ite = c("A","B","C","A","B","C"))
    
    df %>%
      arrange(ori, ifelse(ori == "r", desc(ite), asc(ite)))
    
    #>   grp ori ite
    #> 1   1   f   A
    #> 2   1   f   B
    #> 3   1   f   C
    #> 4   2   r   C
    #> 5   2   r   B
    #> 6   2   r   A
    

    Created on 2022-08-21 by the reprex package (v2.0.1)