diff --git a/README.md b/README.md
index 8f0b0254..71bc9b25 100644
--- a/README.md
+++ b/README.md
@@ -341,18 +341,19 @@ This is what has been implemented so far, is planned or skipped:
| ✅ [#236][]| `removeAt` | `removeAt` | | |
| ✅ [#236][]| `removeManyAt` | `removeManyAt` | | |
| | `replicate` | `replicate` | | |
-| ❓ | `rev` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
+| ✅ | `rev` | `rev` | | materializes sequence before yielding |
| | `scan` | `scan` | `scanAsync` | |
| 🚫 | `scanBack` | | | [note #2](#note2 "Because of the async nature of TaskSeq sequences, iterating from the back would be bad practice. Instead, materialize the sequence to a list or array and then apply the 'Back' iterators.") |
| ✅ [#90][] | `singleton` | `singleton` | | |
| ✅ [#209][]| `skip` | `skip` | | |
| ✅ [#219][]| `skipWhile` | `skipWhile` | `skipWhileAsync` | |
| ✅ [#219][]| | `skipWhileInclusive` | `skipWhileInclusiveAsync` | |
-| ❓ | `sort` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
-| ❓ | `sortBy` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
-| ❓ | `sortByAscending` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
-| ❓ | `sortByDescending` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
-| ❓ | `sortWith` | | | [note #1](#note1 "These functions require a form of pre-materializing through 'TaskSeq.cache', similar to the approach taken in the corresponding 'Seq' functions. It doesn't make much sense to have a cached async sequence. However, 'AsyncSeq' does implement these, so we'll probably do so eventually as well.") |
+| ✅ | `sort` | `sort` | | materializes sequence before yielding |
+| | | `sortDescending` | | materializes sequence before yielding |
+| ✅ | `sortBy` | `sortBy` | `sortByAsync` | materializes sequence before yielding |
+| ✅ | `sortByAscending` | `sortBy` | `sortByAsync` | same as `sortBy`; materializes sequence before yielding |
+| ✅ | `sortByDescending` | `sortByDescending` | `sortByDescendingAsync` | materializes sequence before yielding |
+| ✅ | `sortWith` | `sortWith` | | materializes sequence before yielding |
| | `splitInto` | `splitInto` | | |
| | `sum` | `sum` | | |
| | `sumBy` | `sumBy` | `sumByAsync` | |
diff --git a/global.json b/global.json
index badcd443..cff8de89 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.103",
+ "version": "10.0.102",
"rollForward": "minor"
}
}
diff --git a/release-notes.txt b/release-notes.txt
index 602d3dd2..20740f28 100644
--- a/release-notes.txt
+++ b/release-notes.txt
@@ -5,6 +5,8 @@ Release notes:
- update engineering to .NET 9/10
- adds TaskSeq.scan and TaskSeq.scanAsync, #289
- adds TaskSeq.pairwise, #289
+ - adds TaskSeq.rev, sort, sortDescending, sortBy, sortByAsync,
+ sortByDescending, sortByDescendingAsync, sortWith
- fixes: CancellationToken passed to GetAsyncEnumerator is now honored in MoveNextAsync, #179
0.4.0
diff --git a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
index 4b57dda2..351503de 100644
--- a/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
+++ b/src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj
@@ -21,6 +21,7 @@
+
diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Sort.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Sort.Tests.fs
new file mode 100644
index 00000000..4289d6a0
--- /dev/null
+++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Sort.Tests.fs
@@ -0,0 +1,370 @@
+module TaskSeq.Tests.Sort
+
+open System.Threading.Tasks
+open Xunit
+open FsUnit.Xunit
+
+open FSharp.Control
+
+//
+// TaskSeq.rev / TaskSeq.sort / TaskSeq.sortDescending
+// TaskSeq.sortBy / TaskSeq.sortByAsync
+// TaskSeq.sortByDescending / TaskSeq.sortByDescendingAsync
+// TaskSeq.sortWith
+//
+
+module Rev =
+ module EmptySeq =
+ []
+ let ``TaskSeq-rev with null source raises`` () = assertNullArg <| fun () -> TaskSeq.rev null
+
+ [)>]
+ let ``TaskSeq-rev on empty returns empty`` variant = Gen.getEmptyVariant variant |> TaskSeq.rev |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-rev on single element returns same element`` () = task {
+ let! result = taskSeq { yield 42 } |> TaskSeq.rev |> TaskSeq.toListAsync
+ result |> should equal [ 42 ]
+ }
+
+ []
+ let ``TaskSeq-rev reverses ascending sequence`` () = task {
+ let! result =
+ taskSeq { yield! [ 1..5 ] }
+ |> TaskSeq.rev
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 5; 4; 3; 2; 1 ]
+ }
+
+ []
+ let ``TaskSeq-rev of rev is identity`` () = task {
+ let! result =
+ taskSeq { yield! [ 10; 20; 30 ] }
+ |> TaskSeq.rev
+ |> TaskSeq.rev
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 10; 20; 30 ]
+ }
+
+ [)>]
+ let ``TaskSeq-rev all variants - correct length and reversed order`` variant = task {
+ let! result =
+ Gen.getSeqImmutable variant
+ |> TaskSeq.rev
+ |> TaskSeq.toListAsync
+
+ result |> List.length |> should equal 10
+ result |> List.head |> should equal 10
+ result |> List.last |> should equal 1
+ }
+
+module Sort =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sort with null source raises`` () = assertNullArg <| fun () -> TaskSeq.sort null
+
+ [)>]
+ let ``TaskSeq-sort on empty returns empty`` variant = Gen.getEmptyVariant variant |> TaskSeq.sort |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-sort on single element returns same element`` () = task {
+ let! result = taskSeq { yield 42 } |> TaskSeq.sort |> TaskSeq.toListAsync
+ result |> should equal [ 42 ]
+ }
+
+ []
+ let ``TaskSeq-sort sorts integers ascending`` () = task {
+ let! result =
+ taskSeq { yield! [ 3; 1; 4; 1; 5; 9; 2; 6 ] }
+ |> TaskSeq.sort
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 1; 1; 2; 3; 4; 5; 6; 9 ]
+ }
+
+ []
+ let ``TaskSeq-sort sorts strings lexicographically`` () = task {
+ let! result =
+ taskSeq { yield! [ "banana"; "apple"; "cherry" ] }
+ |> TaskSeq.sort
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ "apple"; "banana"; "cherry" ]
+ }
+
+ []
+ let ``TaskSeq-sort already-sorted sequence stays sorted`` () = task {
+ let! result =
+ taskSeq { yield! [ 1..10 ] }
+ |> TaskSeq.sort
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 1..10 ]
+ }
+
+module SortDescending =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortDescending with null source raises`` () = assertNullArg <| fun () -> TaskSeq.sortDescending null
+
+ [)>]
+ let ``TaskSeq-sortDescending on empty returns empty`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortDescending
+ |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortDescending sorts integers descending`` () = task {
+ let! result =
+ taskSeq { yield! [ 3; 1; 4; 1; 5; 9; 2; 6 ] }
+ |> TaskSeq.sortDescending
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 9; 6; 5; 4; 3; 2; 1; 1 ]
+ }
+
+ []
+ let ``TaskSeq-sortDescending is reverse of sort`` () = task {
+ let input = [ 3; 1; 4; 1; 5; 9; 2; 6 ]
+
+ let! ascending =
+ taskSeq { yield! input }
+ |> TaskSeq.sort
+ |> TaskSeq.toListAsync
+
+ let! descending =
+ taskSeq { yield! input }
+ |> TaskSeq.sortDescending
+ |> TaskSeq.toListAsync
+
+ descending |> should equal (List.rev ascending)
+ }
+
+module SortBy =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortBy with null source raises`` () = assertNullArg <| fun () -> TaskSeq.sortBy id null
+
+ [)>]
+ let ``TaskSeq-sortBy on empty returns empty`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortBy id
+ |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortBy sorts by string length`` () = task {
+ let! result =
+ taskSeq { yield! [ "banana"; "fig"; "apple"; "kiwi" ] }
+ |> TaskSeq.sortBy String.length
+ |> TaskSeq.toListAsync
+
+ result
+ |> List.map String.length
+ |> should equal [ 3; 4; 5; 6 ]
+ }
+
+ []
+ let ``TaskSeq-sortBy sorts tuples by key`` () = task {
+ let! result =
+ taskSeq { yield! [ ("b", 2); ("a", 1); ("c", 3) ] }
+ |> TaskSeq.sortBy fst
+ |> TaskSeq.toListAsync
+
+ result |> List.map fst |> should equal [ "a"; "b"; "c" ]
+ }
+
+ []
+ let ``TaskSeq-sortBy with identity is equivalent to sort`` () = task {
+ let input = [ 5; 3; 8; 1; 4 ]
+
+ let! sorted =
+ taskSeq { yield! input }
+ |> TaskSeq.sort
+ |> TaskSeq.toListAsync
+
+ let! sortedById =
+ taskSeq { yield! input }
+ |> TaskSeq.sortBy id
+ |> TaskSeq.toListAsync
+
+ sortedById |> should equal sorted
+ }
+
+module SortByDescending =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortByDescending with null source raises`` () = assertNullArg <| fun () -> TaskSeq.sortByDescending id null
+
+ [)>]
+ let ``TaskSeq-sortByDescending on empty returns empty`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortByDescending id
+ |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortByDescending sorts by string length descending`` () = task {
+ let! result =
+ taskSeq { yield! [ "banana"; "fig"; "apple"; "kiwi" ] }
+ |> TaskSeq.sortByDescending String.length
+ |> TaskSeq.toListAsync
+
+ result
+ |> List.map String.length
+ |> should equal [ 6; 5; 4; 3 ]
+ }
+
+ []
+ let ``TaskSeq-sortByDescending is reverse of sortBy for same projection`` () = task {
+ let input = [ "banana"; "fig"; "apple"; "kiwi" ]
+
+ let! ascending =
+ taskSeq { yield! input }
+ |> TaskSeq.sortBy String.length
+ |> TaskSeq.toListAsync
+
+ let! descending =
+ taskSeq { yield! input }
+ |> TaskSeq.sortByDescending String.length
+ |> TaskSeq.toListAsync
+
+ descending |> should equal (List.rev ascending)
+ }
+
+module SortByAsync =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortByAsync with null source raises`` () =
+ assertNullArg
+ <| fun () -> TaskSeq.sortByAsync (fun x -> Task.FromResult x) null
+
+ [)>]
+ let ``TaskSeq-sortByAsync on empty returns empty`` variant = task {
+ do!
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortByAsync (fun x -> Task.FromResult x)
+ |> verifyEmpty
+ }
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortByAsync sorts by async key`` () = task {
+ let! result =
+ taskSeq { yield! [ "banana"; "fig"; "apple"; "kiwi" ] }
+ |> TaskSeq.sortByAsync (fun s -> Task.FromResult(String.length s))
+ |> TaskSeq.toListAsync
+
+ result
+ |> List.map String.length
+ |> should equal [ 3; 4; 5; 6 ]
+ }
+
+ []
+ let ``TaskSeq-sortByAsync result matches synchronous sortBy`` () = task {
+ let input = [ 5; 3; 8; 1; 4 ]
+
+ let! syncResult =
+ taskSeq { yield! input }
+ |> TaskSeq.sortBy id
+ |> TaskSeq.toListAsync
+
+ let! asyncResult =
+ taskSeq { yield! input }
+ |> TaskSeq.sortByAsync (fun x -> Task.FromResult x)
+ |> TaskSeq.toListAsync
+
+ asyncResult |> should equal syncResult
+ }
+
+module SortByDescendingAsync =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortByDescendingAsync with null source raises`` () =
+ assertNullArg
+ <| fun () -> TaskSeq.sortByDescendingAsync (fun x -> Task.FromResult x) null
+
+ [)>]
+ let ``TaskSeq-sortByDescendingAsync on empty returns empty`` variant = task {
+ do!
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortByDescendingAsync (fun x -> Task.FromResult x)
+ |> verifyEmpty
+ }
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortByDescendingAsync sorts descending by async key`` () = task {
+ let! result =
+ taskSeq { yield! [ "banana"; "fig"; "apple"; "kiwi" ] }
+ |> TaskSeq.sortByDescendingAsync (fun s -> Task.FromResult(String.length s))
+ |> TaskSeq.toListAsync
+
+ result
+ |> List.map String.length
+ |> should equal [ 6; 5; 4; 3 ]
+ }
+
+ []
+ let ``TaskSeq-sortByDescendingAsync result matches sortByDescending`` () = task {
+ let input = [ 5; 3; 8; 1; 4 ]
+
+ let! syncResult =
+ taskSeq { yield! input }
+ |> TaskSeq.sortByDescending id
+ |> TaskSeq.toListAsync
+
+ let! asyncResult =
+ taskSeq { yield! input }
+ |> TaskSeq.sortByDescendingAsync (fun x -> Task.FromResult x)
+ |> TaskSeq.toListAsync
+
+ asyncResult |> should equal syncResult
+ }
+
+module SortWith =
+ module EmptySeq =
+ []
+ let ``TaskSeq-sortWith with null source raises`` () = assertNullArg <| fun () -> TaskSeq.sortWith compare null
+
+ [)>]
+ let ``TaskSeq-sortWith on empty returns empty`` variant =
+ Gen.getEmptyVariant variant
+ |> TaskSeq.sortWith compare
+ |> verifyEmpty
+
+ module Immutable =
+ []
+ let ``TaskSeq-sortWith with standard compare gives ascending order`` () = task {
+ let! result =
+ taskSeq { yield! [ 3; 1; 4; 1; 5; 9; 2; 6 ] }
+ |> TaskSeq.sortWith compare
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 1; 1; 2; 3; 4; 5; 6; 9 ]
+ }
+
+ []
+ let ``TaskSeq-sortWith with reversed compare gives descending order`` () = task {
+ let! result =
+ taskSeq { yield! [ 3; 1; 4; 1; 5; 9; 2; 6 ] }
+ |> TaskSeq.sortWith (fun a b -> compare b a)
+ |> TaskSeq.toListAsync
+
+ result |> should equal [ 9; 6; 5; 4; 3; 2; 1; 1 ]
+ }
+
+ []
+ let ``TaskSeq-sortWith with custom comparer sorts by absolute value`` () = task {
+ let! result =
+ taskSeq { yield! [ -3; 1; -4; 2; -5 ] }
+ |> TaskSeq.sortWith (fun a b -> compare (abs a) (abs b))
+ |> TaskSeq.toListAsync
+
+ result |> List.map abs |> should equal [ 1; 2; 3; 4; 5 ]
+ }
diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fs b/src/FSharp.Control.TaskSeq/TaskSeq.fs
index 0ff387c6..7786558c 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeq.fs
+++ b/src/FSharp.Control.TaskSeq/TaskSeq.fs
@@ -414,3 +414,16 @@ type TaskSeq private () =
static member scanAsync folder state source = Internal.scan (AsyncFolderAction folder) state source
static member reduce folder source = Internal.reduce (FolderAction folder) source
static member reduceAsync folder source = Internal.reduce (AsyncFolderAction folder) source
+
+ //
+ // sort/rev functions (require full materialisation before streaming)
+ //
+
+ static member rev source = Internal.rev source
+ static member sort source = Internal.sort source
+ static member sortDescending source = Internal.sortDescending source
+ static member sortBy projection source = Internal.sortBy projection source
+ static member sortByDescending projection source = Internal.sortByDescending projection source
+ static member sortByAsync projection source = Internal.sortByAsync projection source
+ static member sortByDescendingAsync projection source = Internal.sortByDescendingAsync projection source
+ static member sortWith comparer source = Internal.sortWith comparer source
diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fsi b/src/FSharp.Control.TaskSeq/TaskSeq.fsi
index d1d8d7c9..44ec6500 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeq.fsi
+++ b/src/FSharp.Control.TaskSeq/TaskSeq.fsi
@@ -1511,3 +1511,97 @@ type TaskSeq =
/// Thrown when the input task sequence is null.
/// Thrown when index is below 0 or greater than source length.
static member updateAt: index: int -> value: 'T -> source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Returns a new task sequence with elements in reverse order. This function requires the full sequence to be
+ /// materialised into memory before streaming the results back.
+ ///
+ ///
+ /// The input task sequence.
+ /// The reversed task sequence.
+ /// Thrown when the input task sequence is null.
+ static member rev: source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in ascending order. This function requires the full sequence to be
+ /// materialised into memory before streaming the sorted results back.
+ /// If the projection function is asynchronous, consider using .
+ ///
+ ///
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sort<'T when 'T: comparison> : source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in descending order. This function requires the full sequence to be
+ /// materialised into memory before streaming the sorted results back.
+ ///
+ ///
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortDescending<'T when 'T: comparison> : source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in ascending order by the given projection. This function requires the
+ /// full sequence to be materialised into memory before streaming the sorted results back.
+ /// If the projection function is asynchronous, consider using .
+ ///
+ ///
+ /// A function to transform elements of the input sequence into the type being compared.
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortBy<'T, 'Key when 'Key: comparison> :
+ projection: ('T -> 'Key) -> source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in descending order by the given projection. This function requires the
+ /// full sequence to be materialised into memory before streaming the sorted results back.
+ /// If the projection function is asynchronous, consider using .
+ ///
+ ///
+ /// A function to transform elements of the input sequence into the type being compared.
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortByDescending<'T, 'Key when 'Key: comparison> :
+ projection: ('T -> 'Key) -> source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in ascending order by the given asynchronous projection. This function
+ /// requires the full sequence to be materialised into memory before streaming the sorted results back.
+ /// If the projection function is synchronous, consider using .
+ ///
+ ///
+ /// An asynchronous function to transform elements of the input sequence into the type being compared.
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortByAsync<'T, 'Key when 'Key: comparison> :
+ projection: ('T -> Task<'Key>) -> source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence in descending order by the given asynchronous projection. This function
+ /// requires the full sequence to be materialised into memory before streaming the sorted results back.
+ /// If the projection function is synchronous, consider using .
+ ///
+ ///
+ /// An asynchronous function to transform elements of the input sequence into the type being compared.
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortByDescendingAsync<'T, 'Key when 'Key: comparison> :
+ projection: ('T -> Task<'Key>) -> source: TaskSeq<'T> -> TaskSeq<'T>
+
+ ///
+ /// Sorts the elements of a task sequence using the given comparison function. This function requires the full
+ /// sequence to be materialised into memory before streaming the sorted results back.
+ ///
+ ///
+ /// A function that compares two elements and returns an integer indicating their relative order.
+ /// The input task sequence.
+ /// The sorted task sequence.
+ /// Thrown when the input task sequence is null.
+ static member sortWith: comparer: ('T -> 'T -> int) -> source: TaskSeq<'T> -> TaskSeq<'T>
diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
index ee7b3df0..aee2877d 100644
--- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
+++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs
@@ -1152,3 +1152,92 @@ module internal TaskSeqInternal =
yield previous, current
maybePrevious <- ValueSome current
}
+
+ let rev (source: TaskSeq<_>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ let arr = resizeArr.ToArray()
+
+ for i = arr.Length - 1 downto 0 do
+ yield arr.[i]
+ }
+
+ let sort (source: TaskSeq<_>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ yield! resizeArr.ToArray() |> Array.sort
+ }
+
+ let sortDescending (source: TaskSeq<_>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ yield! resizeArr.ToArray() |> Array.sortDescending
+ }
+
+ let sortBy (projection: 'T -> 'Key) (source: TaskSeq<'T>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ yield! resizeArr.ToArray() |> Array.sortBy projection
+ }
+
+ let sortByDescending (projection: 'T -> 'Key) (source: TaskSeq<'T>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ yield! resizeArr.ToArray() |> Array.sortByDescending projection
+ }
+
+ let sortByAsync (projection: 'T -> Task<'Key>) (source: TaskSeq<'T>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! pairs = task {
+ let! resizeArr = toResizeArrayAsync source
+ let arr = resizeArr.ToArray()
+ let kvs = ResizeArray(arr.Length)
+
+ for item in arr do
+ let! k = projection item
+ kvs.Add(k, item)
+
+ return kvs.ToArray()
+ }
+
+ yield! pairs |> Array.sortBy fst |> Array.map snd
+ }
+
+ let sortByDescendingAsync (projection: 'T -> Task<'Key>) (source: TaskSeq<'T>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! pairs = task {
+ let! resizeArr = toResizeArrayAsync source
+ let arr = resizeArr.ToArray()
+ let kvs = ResizeArray(arr.Length)
+
+ for item in arr do
+ let! k = projection item
+ kvs.Add(k, item)
+
+ return kvs.ToArray()
+ }
+
+ yield! pairs |> Array.sortByDescending fst |> Array.map snd
+ }
+
+ let sortWith (comparer: 'T -> 'T -> int) (source: TaskSeq<'T>) =
+ checkNonNull (nameof source) source
+
+ taskSeq {
+ let! resizeArr = toResizeArrayAsync source
+ yield! resizeArr.ToArray() |> Array.sortWith comparer
+ }