Skip to content

Commit a7119ca

Browse files
bpe-incomclaude
andauthored
Add partitionResults with single-pass destructuring (#359)
* Add partitionResult * Use single-pass implementations for partitionResults Address review feedback from #358: replace two-pass Array.choose implementations with single-pass alternatives. Array uses ResizeArray, List uses tail-recursive loop, Seq returns seq instead of array. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Implement suggested changes * Add null guards * rename variable * Add docs to gitbook * ReferenceEquals as null guard and missing xml docs * Add Array section to Gitbook --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a934868 commit a7119ca

7 files changed

Lines changed: 222 additions & 0 deletions

File tree

gitbook/SUMMARY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@
2626
* [sequenceResultM](list/sequenceResultM.md)
2727
* [traverseResultA](list/traverseResultA.md)
2828
* [sequenceResultA](list/sequenceResultA.md)
29+
* [partitionResults](list/partitionResults.md)
2930
* Sequences
3031
* [traverseResultM](seq/traverseResultM.md)
3132
* [sequenceResultM](seq/sequenceResultM.md)
3233
* [traverseResultA](seq/traverseResultA.md)
3334
* [sequenceResultA](seq/sequenceResultA.md)
35+
* [partitionResults](seq/partitionResults.md)
36+
* Arrays
37+
* [partitionResults](array/partitionResults.md)
3438
* Transforms
3539
* [ofChoice](result/ofChoice.md)
3640

gitbook/array/partitionResults.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Array.partitionResults
2+
3+
Namespace: `FsToolkit.ErrorHandling`
4+
5+
## Function Signature
6+
7+
```fsharp
8+
Result<'ok, 'error>[] -> 'ok[] * 'error[]
9+
```
10+
11+
Separates an array of `Result` values into a tuple of the `Ok` values and the `Error` values, preserving order within each group.
12+
13+
## Examples
14+
15+
### Example 1
16+
17+
```fsharp
18+
let results = [| Ok 1; Error "bad"; Ok 2; Ok 3; Error "worse" |]
19+
20+
results |> Array.partitionResults
21+
// ([| 1; 2; 3 |], [| "bad"; "worse" |])
22+
```
23+
24+
### Example 2
25+
26+
```fsharp
27+
// string -> Result<int, string>
28+
let tryParseInt str =
29+
match System.Int32.TryParse str with
30+
| true, x -> Ok x
31+
| false, _ -> Error (sprintf "unable to parse '%s' to integer" str)
32+
33+
[| "1"; "foo"; "3"; "bar" |]
34+
|> Array.map tryParseInt
35+
|> Array.partitionResults
36+
// ([| 1; 3 |], [| "unable to parse 'foo' to integer"; "unable to parse 'bar' to integer" |])
37+
```
38+
39+
### Example 3
40+
41+
All Ok values:
42+
43+
```fsharp
44+
[| Ok 1; Ok 2; Ok 3 |] |> Array.partitionResults
45+
// ([| 1; 2; 3 |], [||])
46+
```
47+
48+
All Error values:
49+
50+
```fsharp
51+
[| Error "a"; Error "b" |] |> Array.partitionResults
52+
// ([||], [| "a"; "b" |])
53+
```

gitbook/list/partitionResults.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# List.partitionResults
2+
3+
Namespace: `FsToolkit.ErrorHandling`
4+
5+
## Function Signature
6+
7+
```fsharp
8+
Result<'ok, 'error> list -> 'ok list * 'error list
9+
```
10+
11+
Separates a list of `Result` values into a tuple of the `Ok` values and the `Error` values, preserving order within each group.
12+
13+
## Examples
14+
15+
### Example 1
16+
17+
```fsharp
18+
let results = [Ok 1; Error "bad"; Ok 2; Ok 3; Error "worse"]
19+
20+
results |> List.partitionResults
21+
// ([1; 2; 3], ["bad"; "worse"])
22+
```
23+
24+
### Example 2
25+
26+
```fsharp
27+
// string -> Result<int, string>
28+
let tryParseInt str =
29+
match System.Int32.TryParse str with
30+
| true, x -> Ok x
31+
| false, _ -> Error (sprintf "unable to parse '%s' to integer" str)
32+
33+
["1"; "foo"; "3"; "bar"]
34+
|> List.map tryParseInt
35+
|> List.partitionResults
36+
// ([1; 3], ["unable to parse 'foo' to integer"; "unable to parse 'bar' to integer"])
37+
```
38+
39+
### Example 3
40+
41+
All Ok values:
42+
43+
```fsharp
44+
[Ok 1; Ok 2; Ok 3] |> List.partitionResults
45+
// ([1; 2; 3], [])
46+
```
47+
48+
All Error values:
49+
50+
```fsharp
51+
[Error "a"; Error "b"] |> List.partitionResults
52+
// ([], ["a"; "b"])
53+
```

gitbook/seq/partitionResults.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Seq.partitionResults
2+
3+
Namespace: `FsToolkit.ErrorHandling`
4+
5+
## Function Signature
6+
7+
```fsharp
8+
seq<Result<'ok, 'error>> -> 'ok[] * 'error[]
9+
```
10+
11+
Separates a sequence of `Result` values into a tuple of the `Ok` values and the `Error` values as arrays, preserving order within each group.
12+
13+
See also [Array.partitionResults](../array/partitionResults.md).
14+
15+
## Examples
16+
17+
### Example 1
18+
19+
```fsharp
20+
let results = seq { Ok 1; Error "bad"; Ok 2; Ok 3; Error "worse" }
21+
22+
results |> Seq.partitionResults
23+
// ([| 1; 2; 3 |], [| "bad"; "worse" |])
24+
```
25+
26+
### Example 2
27+
28+
```fsharp
29+
// string -> Result<int, string>
30+
let tryParseInt str =
31+
match System.Int32.TryParse str with
32+
| true, x -> Ok x
33+
| false, _ -> Error $"unable to parse '{str}' to integer"
34+
35+
["1"; "foo"; "3"; "bar"]
36+
|> Seq.map tryParseInt
37+
|> Seq.partitionResults
38+
// ([| 1; 3 |], [| "unable to parse 'foo' to integer"; "unable to parse 'bar' to integer" |])
39+
```
40+
41+
### Example 3
42+
43+
All Ok values:
44+
45+
```fsharp
46+
seq { Ok 1; Ok 2; Ok 3 } |> Seq.partitionResults
47+
// ([| 1; 2; 3 |], [||])
48+
```
49+
50+
All Error values:
51+
52+
```fsharp
53+
seq { Error "a"; Error "b" } |> Seq.partitionResults
54+
// ([||], [| "a"; "b" |])
55+
```

src/FsToolkit.ErrorHandling/Array.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,22 @@ module Array =
233233
let sequenceVOptionM xs = traverseVOptionM id xs
234234

235235
#endif
236+
237+
/// <summary>
238+
/// Partitions an array of results into a tuple of the ok values and the error values.
239+
/// </summary>
240+
/// <param name="input">The input array of results.</param>
241+
/// <returns>A tuple where the first element is an array of all Ok values and the second is an array of all Error values.</returns>
242+
let partitionResults (input: Result<'ok, 'error>[]) : 'ok[] * 'error[] =
243+
if System.Object.ReferenceEquals(input, null) then
244+
nullArg (nameof input)
245+
246+
let oks = ResizeArray()
247+
let errors = ResizeArray()
248+
249+
for x in input do
250+
match x with
251+
| Ok v -> oks.Add v
252+
| Error e -> errors.Add e
253+
254+
oks.ToArray(), errors.ToArray()

src/FsToolkit.ErrorHandling/List.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,22 @@ module List =
274274

275275

276276
#endif
277+
278+
/// <summary>
279+
/// Partitions a list of results into a tuple of the ok values and the error values.
280+
/// </summary>
281+
/// <param name="input">The input list of results.</param>
282+
/// <returns>A tuple where the first element is a list of all Ok values and the second is a list of all Error values.</returns>
283+
let partitionResults (input: Result<'ok, 'error> list) : 'ok list * 'error list =
284+
if System.Object.ReferenceEquals(input, null) then
285+
nullArg (nameof input)
286+
287+
let oks = ResizeArray()
288+
let errors = ResizeArray()
289+
290+
for x in input do
291+
match x with
292+
| Ok v -> oks.Add v
293+
| Error e -> errors.Add e
294+
295+
List.ofSeq oks, List.ofSeq errors

src/FsToolkit.ErrorHandling/Seq.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,3 +501,22 @@ let traverseVOptionM f xs =
501501
let sequenceVOptionM xs = traverseVOptionM id xs
502502

503503
#endif
504+
505+
/// <summary>
506+
/// Partitions a sequence of results into a tuple of the ok values and the error values.
507+
/// </summary>
508+
/// <param name="input">The input sequence of results.</param>
509+
/// <returns>A tuple where the first element is an array of all Ok values and the second is an array of all Error values.</returns>
510+
let partitionResults (input: SeqNull<Result<'ok, 'error>>) : 'ok[] * 'error[] =
511+
if isNull input then
512+
nullArg (nameof input)
513+
514+
let oks = ResizeArray()
515+
let errors = ResizeArray()
516+
517+
for x in input do
518+
match x with
519+
| Ok v -> oks.Add v
520+
| Error e -> errors.Add e
521+
522+
oks.ToArray(), errors.ToArray()

0 commit comments

Comments
 (0)