Skip to content

Commit 804baaa

Browse files
authored
Merge branch 'main' into repo-assist/findback-2026-04-03-8769885a31ab339d
2 parents f7ed006 + ead77d6 commit 804baaa

4 files changed

Lines changed: 81 additions & 0 deletions

File tree

RELEASE_NOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
* Added `AsyncSeq.tryFindBackAsync` — async-predicate variant of `tryFindBack`.
55
* Added `AsyncSeq.findBack` — returns the last element for which the predicate returns true; raises `KeyNotFoundException` if no match. Mirrors `Array.findBack` / `List.findBack`.
66
* Added `AsyncSeq.findBackAsync` — async-predicate variant of `findBack`.
7+
* Added `AsyncSeq.sortAsync` — asynchronous variant of `sort` returning `Async<'T[]>`, avoiding `Async.RunSynchronously` in async workflows.
8+
* Added `AsyncSeq.sortByAsync` — asynchronous variant of `sortBy` returning `Async<'T[]>`.
9+
* Added `AsyncSeq.sortDescendingAsync` — asynchronous variant of `sortDescending` returning `Async<'T[]>`.
10+
* Added `AsyncSeq.sortByDescendingAsync` — asynchronous variant of `sortByDescending` returning `Async<'T[]>`.
11+
* Added `AsyncSeq.sortWithAsync` — asynchronous variant of `sortWith` returning `Async<'T[]>`.
712

813
### 4.11.0
914

src/FSharp.Control.AsyncSeq/AsyncSeq.fs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,21 @@ module AsyncSeq =
22792279
let sortWith (comparer:'T -> 'T -> int) (source:AsyncSeq<'T>) : array<'T> =
22802280
toSortedSeq (Array.sortWith comparer) source
22812281

2282+
let sortAsync (source:AsyncSeq<'T>) : Async<array<'T>> when 'T : comparison =
2283+
toArrayAsync source |> Async.map Array.sort
2284+
2285+
let sortByAsync (projection:'T -> 'Key) (source:AsyncSeq<'T>) : Async<array<'T>> when 'Key : comparison =
2286+
toArrayAsync source |> Async.map (Array.sortBy projection)
2287+
2288+
let sortDescendingAsync (source:AsyncSeq<'T>) : Async<array<'T>> when 'T : comparison =
2289+
toArrayAsync source |> Async.map Array.sortDescending
2290+
2291+
let sortByDescendingAsync (projection:'T -> 'Key) (source:AsyncSeq<'T>) : Async<array<'T>> when 'Key : comparison =
2292+
toArrayAsync source |> Async.map (Array.sortByDescending projection)
2293+
2294+
let sortWithAsync (comparer:'T -> 'T -> int) (source:AsyncSeq<'T>) : Async<array<'T>> =
2295+
toArrayAsync source |> Async.map (Array.sortWith comparer)
2296+
22822297
let rev (source: AsyncSeq<'T>) : AsyncSeq<'T> = asyncSeq {
22832298
let! arr = toArrayAsync source
22842299
for i in arr.Length - 1 .. -1 .. 0 do

src/FSharp.Control.AsyncSeq/AsyncSeq.fsi

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,26 @@ module AsyncSeq =
746746
/// large or infinite sequences.
747747
val sortWith : comparer:('T -> 'T -> int) -> source:AsyncSeq<'T> -> array<'T>
748748

749+
/// Asynchronously sorts the given async sequence and returns an Async<array<'T>>.
750+
/// Prefer this over sortAsync when composing async workflows.
751+
val sortAsync : source:AsyncSeq<'T> -> Async<array<'T>> when 'T : comparison
752+
753+
/// Asynchronously applies a key-generating function to each element of an AsyncSeq and returns
754+
/// an Async<array<'T>> ordered by keys. Prefer this over sortBy when composing async workflows.
755+
val sortByAsync : projection:('T -> 'Key) -> source:AsyncSeq<'T> -> Async<array<'T>> when 'Key : comparison
756+
757+
/// Asynchronously sorts the given async sequence in descending order and returns an Async<array<'T>>.
758+
/// Prefer this over sortDescending when composing async workflows.
759+
val sortDescendingAsync : source:AsyncSeq<'T> -> Async<array<'T>> when 'T : comparison
760+
761+
/// Asynchronously applies a key-generating function to each element of an AsyncSeq and returns
762+
/// an Async<array<'T>> ordered descending by keys. Prefer this over sortByDescending when composing async workflows.
763+
val sortByDescendingAsync : projection:('T -> 'Key) -> source:AsyncSeq<'T> -> Async<array<'T>> when 'Key : comparison
764+
765+
/// Asynchronously sorts the given async sequence using the given comparison function and returns
766+
/// an Async<array<'T>>. Prefer this over sortWith when composing async workflows.
767+
val sortWithAsync : comparer:('T -> 'T -> int) -> source:AsyncSeq<'T> -> Async<array<'T>>
768+
749769
/// Returns a new async sequence with the elements in reverse order. The entire source
750770
/// sequence is buffered before yielding any elements, mirroring Seq.rev.
751771
/// This function should not be used with large or infinite sequences.

tests/FSharp.Control.AsyncSeq.Tests/AsyncSeqTests.fs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3536,6 +3536,47 @@ let ``AsyncSeq.sortWith returns empty array for empty sequence`` () =
35363536
let result = AsyncSeq.sortWith compare AsyncSeq.empty<int>
35373537
Assert.AreEqual([||], result)
35383538

3539+
// ===== sortAsync / sortByAsync / sortDescendingAsync / sortByDescendingAsync / sortWithAsync =====
3540+
3541+
[<Test>]
3542+
let ``AsyncSeq.sortAsync sorts in ascending order`` () =
3543+
let result = AsyncSeq.ofSeq [ 3; 1; 4; 1; 5; 9 ] |> AsyncSeq.sortAsync |> Async.RunSynchronously
3544+
Assert.AreEqual([| 1; 1; 3; 4; 5; 9 |], result)
3545+
3546+
[<Test>]
3547+
let ``AsyncSeq.sortAsync returns empty array for empty sequence`` () =
3548+
let result = AsyncSeq.empty<int> |> AsyncSeq.sortAsync |> Async.RunSynchronously
3549+
Assert.AreEqual([||], result)
3550+
3551+
[<Test>]
3552+
let ``AsyncSeq.sortByAsync sorts by projected key`` () =
3553+
let result =
3554+
AsyncSeq.ofSeq [ "banana"; "apple"; "cherry" ]
3555+
|> AsyncSeq.sortByAsync (fun s -> s.Length)
3556+
|> Async.RunSynchronously
3557+
Assert.AreEqual([| "apple"; "banana"; "cherry" |], result)
3558+
3559+
[<Test>]
3560+
let ``AsyncSeq.sortDescendingAsync sorts in descending order`` () =
3561+
let result = AsyncSeq.ofSeq [ 3; 1; 4; 1; 5 ] |> AsyncSeq.sortDescendingAsync |> Async.RunSynchronously
3562+
Assert.AreEqual([| 5; 4; 3; 1; 1 |], result)
3563+
3564+
[<Test>]
3565+
let ``AsyncSeq.sortByDescendingAsync sorts by projected key descending`` () =
3566+
let result =
3567+
AsyncSeq.ofSeq [ "apple"; "banana"; "fig" ]
3568+
|> AsyncSeq.sortByDescendingAsync (fun s -> s.Length)
3569+
|> Async.RunSynchronously
3570+
Assert.AreEqual([| "banana"; "apple"; "fig" |], result)
3571+
3572+
[<Test>]
3573+
let ``AsyncSeq.sortWithAsync sorts using custom comparer`` () =
3574+
let result =
3575+
AsyncSeq.ofSeq [ 3; 1; 4; 1; 5 ]
3576+
|> AsyncSeq.sortWithAsync (fun a b -> compare b a)
3577+
|> Async.RunSynchronously
3578+
Assert.AreEqual([| 5; 4; 3; 1; 1 |], result)
3579+
35393580
// ── AsyncSeq.mapFold ──────────────────────────────────────────────────────────
35403581

35413582
[<Test>]

0 commit comments

Comments
 (0)