2010-06-24 19 views
20

Jestem całkiem nowy dla F # i przyszedł przez funkcję Seq.sortBy jednak sortuje moją listę w porządku rosnącym. Jak mogę go posortować w porządku malejącym, używając Seq.sort?F # Seq.sortBy w porządku malejącym

Na przykład kod Przykładem może być ...

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

daje mi moc 1 2 3 4 5 6 7 8 9 10, kiedy naprawdę chcesz to zrobić to od 10 do 1.

Odpowiedz

20

Patrząc na inne odpowiedzi, uważaj jednoargumentowy minus i 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|] 

Chyba rzeczywiście chcesz negatywny-X-minus jeden :

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

za zawinięcie około typu integer, który obejmuje -2^N..2^N-1.

+2

Brian, mam nadzieję, że nie masz nic przeciwko, ale dodałem komentarze pokazujące wyjście. – gradbot

+0

świetnie, dzięki ... – Brian

+1

Podobnie jak sidenote '-x-1 = ~~~ x' ponieważ' -x = ~~~ x + 1'. Zobacz [Uzupełnienie dwóch] (https://en.wikipedia.org/wiki/Two%27s_complement). Więc możesz skrócić '(fun x -> -x - 1)' do po prostu '(~~~)' jeśli chcesz. – FooBarTheLittle

6

można rozwiązać ten problem poprzez dostarczenie negatywnego klucza

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

również jest nieco łatwiej (i wpisać bezpieczniejszy), aby korzystać z funkcji printf do wyświetlania tekstu w F #. Na przykład

let DisplayList = 
    seq { 0..10 } 
    |> Seq.sortBy (fun x -> -x) 
    |> Seq.iter (printfn "%d") 
+0

Dzięki za przykłady –

+0

Klucz negatywny nie pomaga ani nie działa dla 'DateTime' niestety – Maslow

18

jeszcze krócej:

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

To jest fajna sztuczka – JaredPar

5

Jeśli wiesz, z wyprzedzeniem, że będziesz mieć stosunkowo małą sekwencję, myślę, że jest to bardziej czytelne ...

let x = seq { 0.. 10 } |> Seq.toArray |> Array.rev

Oczywiście, nie jest wskazane, jeśli masz potencjalnie bardzo duża sekwencja.

15

Najpierw rozszerzmy Seq o funkcję sortWith, taką samą jak lista i macierz.

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

Następnie niech przedłużyć Operators z często przydatnych flip funkcji.

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

Teraz możemy wykorzystać funkcję rodzajowe compare generic (można użyć dowolnej kolejności to z porównywalnych elementów) i sejf (w odniesieniu do obserwacji Briana) odwrotna kolejność sortowania.

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

Dzięki za sugestię. Daję ci +1 za przykład rozszerzenia –

8

Inną opcją jest owinąć 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) 
+0

masz literówkę: powinien to być Seq.sortByDesc (fun x -> x). ale w rzeczywistości można po prostu użyć funkcji "id": Seq.sortByDesc id –

+0

Naprawiono, dziękuję. Po prostu użyłem tego, co Mark używał dla spójności, ale tak "dobrze" dobrze wiedzieć. – dahlbyk

+0

Dzięki za przykład –

4

rozwiązania wykorzystujące jednoargumentowy minus: (fun x -> -x - 1) i (fun x -> -x) nie działają, gdy masz niepodpisanych typy:

let a = [| 0uy; 255uy; 254uy; 1uy |] 
printfn "%A" (a |> Array.sortBy (fun x -> -x - 1)) 
// error FS0001: The type 'byte' does not support the operator '~-' 

Zamiast możemy użyć faktu, że -x = ~~~x + 1 gdzie ~~~ jest ab operator negacji itwise i tym samym -x - 1 = ~~~x.Tak krótki rozwiązanie, które działa zarówno podpisanych i niepodpisanych typów:

Array.sortBy (~~~) // equivalent to Array.sortBy (fun x -> ~~~x) 

Przykłady:

let a = [| 0uy; 255uy; 254uy; 1uy |] 
printfn "%A" (a |> Array.sortBy (~~~)) 
// [|255uy; 254uy; 1uy; 0uy|] 
let a = [| 1; -1; System.Int32.MinValue; 0; System.Int32.MaxValue; 1 |] 
printfn "%A" (a |> Array.sortBy (~~~)) 
// [|2147483647; 1; 1; 0; -1; -2147483648|] 
Powiązane problemy