Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion for a sort function #1042

Open
jmoggridge opened this issue Jan 6, 2023 · 1 comment
Open

Suggestion for a sort function #1042

jmoggridge opened this issue Jan 6, 2023 · 1 comment
Labels
feature a feature request or enhancement list 🧦

Comments

@jmoggridge
Copy link

jmoggridge commented Jan 6, 2023

In javascript, there is a built-in function Array.prototype.sort() that works on an array (like an R list) and takes a user-defined binary function to define ordering.

my_array.sort((a, b) => some_function(a, b))

Base R functions sort and order accept atomic vectors only. To sort lists, the user needs to use a combination of indexing with [ and order on some expression. For example, imagine we wanted to sort a list of vectors by length...

x <- list(letters[1:2], letters[1:4], letters, LETTERS) 
sorted_x <- my_list[order(sapply(my_list, length))]

The tidy approach could use dplyr::arrange on a tibble to sort the list-column.

sorted_x <- tibble(x = x) |> 
  mutate(length = sapply(x, length)) |> 
  arrange(length) |> 
  pull(x)

The proposed purrr function would sort a list based on a user-provided function to determine precedence.

# accept a binary function for complex comparisons
sorted_x <- sort_list(.x = x, .f = \(a,b) length(a) < length(b))

# accept a unary function that evaluates to a `sort`-able atomic vector
sorted_x <- sort_list(x, .f = \(a) length(a))

This is a reprex to illustrate a simple implementation and use case.

# very minimal implementation of proposed function using quicksort
sort_list <- function(.x, .f) {
  if (length(.x) <= 1)  return(.x)
  if (length(formals(.f)) == 1)  return(.x[order(sapply(.x, .f))])
  pivot <- .x[[1]]
  items <- .x[-1]
  has_precedence <- vapply(items, \(item) .f(item, pivot), logical(1L))  
  before <- sort_list(items[which(has_precedence)], .f)
  after <- sort_list(items[which(!has_precedence)], .f)
  c(before, list(pivot), after)
}

# eg, say need to sort a list of vectors by length
x <- list(letters, letters[1:2], letters[1:4], LETTERS) 

# use proposed function to sort list
x |> sort_list(\(a, b) length(a) < length(b))
x |> sort_list(\(a) length(a))

Thanks for your consideration! I'm a huge fan of purrr and tidyverse.

@py-b
Copy link

py-b commented Jan 27, 2023

You can use this if you wish : https://py_b.gitlab.io/funprog/reference/sort_by.html
(a package of mine)

@hadley hadley added feature a feature request or enhancement list 🧦 labels Jul 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement list 🧦
Projects
None yet
Development

No branches or pull requests

3 participants