F# Seq.sortBy in descending order

12,128

Solution 1

Looking at the other answers, beware unary minus and MININT:

let a = [| 1; -1; System.Int32.MinValue; 0; System.Int32.MaxValue; 1 |]

printfn "%A" (a |> Array.sortBy (fun x -> x))
// [|-2147483648; -1; 0; 1; 1; 2147483647|]

printfn "%A" (a |> Array.sortBy (fun x -> -x))  // uh-oh!
// [|-2147483648; 2147483647; 1; 1; 0; -1|]

I think you actually want negative-x-minus-one:

printfn "%A" (a |> Array.sortBy (fun x -> -x - 1))
// [|2147483647; 1; 1; 0; -1; -2147483648|]

for a wraparound integer type that spans -2^N..2^N-1.

Solution 2

F# 4.0 (Visual Studio 2015) introduced Seq.sortByDescending and Seq.sortDescending

let DisplayList =
    seq { 0..10 }
    |> Seq.sortDescending         ' or |> Seq.sortByDescending id
    |> Seq.iter Console.WriteLine

See https://github.com/Microsoft/visualfsharp/wiki/F%23-4.0-Status and https://github.com/fsharp/FSharpLangDesign/blob/master/FSharp-4.0/ListSeqArrayAdditions.md

Solution 3

Even shorter:

seq { 0..10 } 
    |> Seq.sortBy (~-)    // Unary minus
    |> Seq.iter (printfn "%d")

Solution 4

First, let's extend Seq with a sortWith function same as List and Array have.

namespace Microsoft.FSharp.Collections
module Seq =
    let sortWith f e = 
        let e' = e |> Seq.toArray
        e' |> Array.sortInPlaceWith f
        e' |> Seq.readonly

Next, let's extend Operators with an often useful flip function.

namespace Microsoft.FSharp.Core
module Operators =
    let flip f x y = f y x

Now, we can leverage the generic compare function for generic (you can use this with any sequence of comparable elements) and safe (in regard to Brian's observation) reverse sequence sort.

{0..10}
|> Seq.sortWith (flip compare)
|> Seq.iter (printfn "%A")

Solution 5

Another option is to wrap System.Linq.Enumerable.OrderByDescending():

// #r "System.Core"
module Seq =
    let sortByDesc f s = Enumerable.OrderByDescending(s, new Func<'a, 'b>(f))

{0..10} |> Seq.sortByDesc (fun x -> x)
Share:
12,128

Related videos on Youtube

Mark Pearl
Author by

Mark Pearl

Updated on July 28, 2020

Comments

  • Mark Pearl
    Mark Pearl over 3 years

    I am fairly new to F# and came by the Seq.sortBy function however it is sorting my list in ascending order. How do I get it to sort in descending order using the Seq.sort?

    For instance an example code would be...

    let DisplayList =
    seq{0..10}
    |> Seq.sortBy(fun x -> x)
    |> Seq.iter(fun x -> Console.WriteLine(x.ToString()))
    

    gives me an output of 1 2 3 4 5 6 7 8 9 10, when I really want it to do it from 10 to 1.

  • gradbot
    gradbot almost 14 years
    Brian, I hope you don't mind but I added comments showing the output.
  • Stephen Swensen
    Stephen Swensen almost 14 years
    you have a typo: it should be Seq.sortByDesc (fun x -> x). but actually, you can just use the 'id' function: Seq.sortByDesc id
  • dahlbyk
    dahlbyk almost 14 years
    Fixed, thanks. I just used what Mark used for consistency, but yeah id is good to know.
  • Mark Pearl
    Mark Pearl almost 14 years
    Thanks for the suggestion. I'm giving you +1 for the example of extending
  • jbtule
    jbtule about 10 years
    I have a library that does this for most of the linq chaining methods. jbtule.github.io/ComposableExtensions
  • Nicolas Fall
    Nicolas Fall over 8 years
    negative key doesn't help or work for DateTime unfortunately
  • FooBarTheLittle
    FooBarTheLittle about 8 years
    Just as a sidenote -x-1 = ~~~x because -x=~~~x+1. See Two's complement. So you can shorten (fun x -> -x - 1) to simply (~~~) if you like.

Related