F# Seq.sortBy in descending order
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)
Related videos on Youtube
Mark Pearl
Updated on July 28, 2020Comments
-
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 almost 14 yearsBrian, I hope you don't mind but I added comments showing the output.
-
Stephen Swensen almost 14 yearsyou have a typo: it should be Seq.sortByDesc (fun x -> x). but actually, you can just use the 'id' function: Seq.sortByDesc id
-
dahlbyk almost 14 yearsFixed, thanks. I just used what Mark used for consistency, but yeah
id
is good to know. -
Mark Pearl almost 14 yearsThanks for the suggestion. I'm giving you +1 for the example of extending
-
jbtule about 10 yearsI have a library that does this for most of the linq chaining methods. jbtule.github.io/ComposableExtensions
-
Nicolas Fall over 8 yearsnegative key doesn't help or work for
DateTime
unfortunately -
FooBarTheLittle about 8 yearsJust 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.