diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 0c575f0..73d8504 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,10 +3,11 @@
"isRoot": true,
"tools": {
"fable": {
- "version": "4.0.6",
+ "version": "4.24.0",
"commands": [
"fable"
- ]
+ ],
+ "rollForward": false
}
}
}
\ No newline at end of file
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 6f1dedc..5cd8ac3 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -12,15 +12,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.x.x
+ dotnet-version: 8.x.x
- name: Restore fable
run: dotnet tool restore
- name: Setup Node.js environment
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: 16
- name: install node modules
@@ -36,15 +36,15 @@ jobs:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.x.x
+ dotnet-version: 8.x.x
- name: Restore fable
run: dotnet tool restore
- name: Setup Node.js environment
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
node-version: 16
- name: install node modules
diff --git a/FSharpAux.sln b/FSharpAux.sln
index 93d437f..52d3934 100644
--- a/FSharpAux.sln
+++ b/FSharpAux.sln
@@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{7C6D08
ProjectSection(SolutionItems) = preProject
build.cmd = build.cmd
build.sh = build.sh
+ .config\dotnet-tools.json = .config\dotnet-tools.json
+ global.json = global.json
package.json = package.json
EndProjectSection
EndProject
diff --git a/README.md b/README.md
index 5d5fa4d..0460bae 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ end
### Requirements
-- .Net 6.0
+- .Net 8.0
- node.js ~16 (higher might work) [only for fable testing]
- npm ~8 (higher might work) [only for fable testing]
diff --git a/build.cmd b/build.cmd
index 97d967d..8d82883 100644
--- a/build.cmd
+++ b/build.cmd
@@ -1,4 +1,3 @@
@echo off
-cls
dotnet run --project ./build/build.fsproj %*
\ No newline at end of file
diff --git a/build/BasicTasks.fs b/build/BasicTasks.fs
index d7f28ad..768dcd8 100644
--- a/build/BasicTasks.fs
+++ b/build/BasicTasks.fs
@@ -26,5 +26,19 @@ let clean = BuildTask.create "Clean" [] {
let build = BuildTask.create "Build" [clean] {
solutionFile
- |> DotNet.build id
+ |> DotNet.build (fun p ->
+ let msBuildParams =
+ {p.MSBuildParams with
+ Properties = ([
+ "warnon", "3390"
+ ])
+ DisableInternalBinLog = true
+ }
+ {
+ p with
+ MSBuildParams = msBuildParams
+
+ }
+ |> DotNet.Options.withCustomParams (Some "-tl")
+ )
}
\ No newline at end of file
diff --git a/build/PackageTasks.fs b/build/PackageTasks.fs
index d51d99a..29e9ec9 100644
--- a/build/PackageTasks.fs
+++ b/build/PackageTasks.fs
@@ -8,6 +8,7 @@ open TestTasks
open BlackFox.Fake
open Fake.Core
+open Fake.DotNet
open Fake.IO.Globbing.Operators
let pack = BuildTask.create "Pack" [clean; build; runTests] {
@@ -22,12 +23,14 @@ let pack = BuildTask.create "Pack" [clean; build; runTests] {
"Version",stableVersionTag
"PackageReleaseNotes", (release.Notes |> String.concat "\r\n")
] @ p.MSBuildParams.Properties)
+ DisableInternalBinLog = true
}
{
p with
MSBuildParams = msBuildParams
OutputPath = Some pkgDir
}
+ |> DotNet.Options.withCustomParams (Some "--no-dependencies -tl")
))
else failwith "aborted"
}
@@ -44,6 +47,7 @@ let packPrerelease = BuildTask.create "PackPrerelease" [setPrereleaseTag; clean;
"Version", prereleaseTag
"PackageReleaseNotes", (release.Notes |> String.toLines )
] @ p.MSBuildParams.Properties)
+ DisableInternalBinLog = true
}
{
p with
@@ -51,6 +55,7 @@ let packPrerelease = BuildTask.create "PackPrerelease" [setPrereleaseTag; clean;
OutputPath = Some pkgDir
MSBuildParams = msBuildParams
}
+ |> DotNet.Options.withCustomParams (Some "--no-dependencies -tl")
))
else
failwith "aborted"
diff --git a/build/TestTasks.fs b/build/TestTasks.fs
index f0732c2..1dcd93d 100644
--- a/build/TestTasks.fs
+++ b/build/TestTasks.fs
@@ -131,6 +131,7 @@ module RunTests =
Logger = Some "console;verbosity=detailed"
Configuration = DotNet.BuildConfiguration.fromString configuration
NoBuild = true
+ MSBuildParams = { testParams.MSBuildParams with DisableInternalBinLog = true }
}
) testProject
)
diff --git a/build/build.fsproj b/build/build.fsproj
index 43ead2f..9e203de 100644
--- a/build/build.fsproj
+++ b/build/build.fsproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
Exe
@@ -18,15 +18,15 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/global.json b/global.json
index 74536f9..b2ede13 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "6.0.100",
+ "version": "8.0.100",
"rollForward": "latestMinor"
}
}
\ No newline at end of file
diff --git a/src/FSharpAux.Core/Seq.fs b/src/FSharpAux.Core/Seq.fs
index a7c2466..bd4e1cf 100644
--- a/src/FSharpAux.Core/Seq.fs
+++ b/src/FSharpAux.Core/Seq.fs
@@ -110,6 +110,40 @@ module Seq =
hsSs.IntersectWith largerSeq
hsSs
+ ///
+ /// Divides the input sequence into chunks by a key projection function.
+ ///
+ /// A new chunk is created each time the projection function returns a new value, and the resulting chunks are tupled with their keys.
+ ///
+ /// Example: Seq.chunkBy isOdd [3;3;2;4;1;2] = seq [(true, [3; 3]); (false, [2; 4]); (true, [1]); (false, [2])]
+ ///
+ /// The function to determine if an element creates a new chunk
+ ///
+ let chunkBy (projection: 'T -> 'Key) (source: seq<'T>) =
+ seq {
+ use e = source.GetEnumerator ()
+ if e.MoveNext () then
+ // the key of the current chunk
+ let mutable chunkKey = projection e.Current
+ // the members of the current chunk
+ let mutable members = ResizeArray ()
+ members.Add e.Current
+
+ while e.MoveNext () do
+ let currentKey = projection e.Current
+ if chunkKey = currentKey then
+ // add item to current chunk if projection returns the chunk key again
+ members.Add e.Current
+ else
+ // yield current chunk and start a new one if projection returns a new key
+ yield chunkKey, members |> Seq.cast<'T>
+ chunkKey <- currentKey
+ members <- ResizeArray ()
+ members.Add e.Current
+
+ yield chunkKey, members |> Seq.cast<'T>
+ }
+
// // Without continuation passing
// let groupWhen f (input:seq<_>) = seq {
diff --git a/tests/FSharpAux.Core.Tests/FSharpAux.Core.Tests.fsproj b/tests/FSharpAux.Core.Tests/FSharpAux.Core.Tests.fsproj
index d75fea1..aa9bc91 100644
--- a/tests/FSharpAux.Core.Tests/FSharpAux.Core.Tests.fsproj
+++ b/tests/FSharpAux.Core.Tests/FSharpAux.Core.Tests.fsproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net8.0
false
@@ -17,15 +17,15 @@
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/tests/FSharpAux.Core.Tests/SeqTests.fs b/tests/FSharpAux.Core.Tests/SeqTests.fs
index ec3e4ec..8155a43 100644
--- a/tests/FSharpAux.Core.Tests/SeqTests.fs
+++ b/tests/FSharpAux.Core.Tests/SeqTests.fs
@@ -13,6 +13,7 @@ let private testSeq3 = seq {3; 3; 2; 4; 1; 1}
let private testSeq4 = seq {3; 3; 2; 4; 2; 2}
let private testSeq5 = seq {3; 3; 2; 4; 2; 1}
let private testSeq6 = seq {6; 6; 2; 4; 2; 8}
+let private testSeq7 = seq {"2"; "A"; "A"; "B"; "B"; "C"; "D"}
let private testSeq2_groupWhen_Equal = seq {seq {3}; seq {3; 2; 4}; seq {1; 2}}
let private testSeq2_groupWhen_NotEqual = seq {seq {3}; seq {3; 2; 4}; seq {1}; seq {2}}
@@ -23,45 +24,61 @@ let private testSeq4_groupWhen_NotEqual = seq {seq {3}; seq {3; 2; 4; 2}
let private testSeq5_groupWhen_Equal = seq {seq {3}; seq {3; 2; 4; 2}; seq {1}}
let private testSeq5_groupWhen_NotEqual = seq {seq {3}; seq {3; 2; 4; 2; 1}}
+let private testSeq2_chunkByIsOdd = seq {(true, seq {3; 3}); (false, seq {2; 4}); (true, seq {1}); (false, seq {2})}
+let private testSeq6_chunkByIsOdd = seq {(false, seq {6; 6; 2; 4; 2; 8})}
+let private testSeq7_chunkById = seq {("2", seq {"2"}); ("A", seq {"A"; "A"}); ("B", seq {"B"; "B"}); ("C", seq {"C"}); ("D", seq {"D"})}
+
// helper functions
let private list s = Seq.toList s
let private list2 s = Seq.map (Seq.toList) s |> Seq.toList
+let private list2Tpl (s: seq<'Key*seq<'Items>>) = Seq.map (fun (k, i) -> k, i |> Seq.toList) s |> Seq.toList
+let isOdd = fun n -> n % 2 <> 0
let seqTests =
testList "SeqTests" [
- let isOdd = fun n -> n % 2 <> 0
testList "Seq.groupWhen" [
testCase "returns correct jagged list, case1: [3; 3; 2; 4; 1; 2]" (fun _ ->
- Expect.equal (testSeq2 |> Seq.groupWhen isOdd |> list2) (testSeq2_groupWhen_Equal |> list2) "Seq.groupWhen did return correct jagged list"
+ Expect.equal (testSeq2 |> Seq.groupWhen isOdd |> list2) (testSeq2_groupWhen_Equal |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "does not return incorrect jagged list, case1: [3; 3; 2; 4; 1; 2]" (fun _ ->
- Expect.notEqual (testSeq2 |> Seq.groupWhen isOdd |> list2) (testSeq2_groupWhen_NotEqual |> list2) "Seq.groupWhen did not return incorrect jagged list"
+ Expect.notEqual (testSeq2 |> Seq.groupWhen isOdd |> list2) (testSeq2_groupWhen_NotEqual |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "returns correct jagged list, case2: [3; 3; 2; 4; 1; 1]" (fun _ ->
- Expect.equal (testSeq3 |> Seq.groupWhen isOdd |> list2) (testSeq3_groupWhen_Equal |> list2) "Seq.groupWhen did return correct jagged list"
+ Expect.equal (testSeq3 |> Seq.groupWhen isOdd |> list2) (testSeq3_groupWhen_Equal |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "does not return incorrect jagged list, case2: [3; 3; 2; 4; 1; 1]" (fun _ ->
- Expect.notEqual (testSeq3 |> Seq.groupWhen isOdd |> list2) (testSeq3_groupWhen_NotEqual |> list2) "Seq.groupWhen did not return incorrect jagged list"
+ Expect.notEqual (testSeq3 |> Seq.groupWhen isOdd |> list2) (testSeq3_groupWhen_NotEqual |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "returns correct jagged list, case3: [3; 3; 2; 4; 2; 2]" (fun _ ->
- Expect.equal (testSeq4 |> Seq.groupWhen isOdd |> list2) (testSeq4_groupWhen_Equal |> list2) "Seq.groupWhen did return correct jagged list"
+ Expect.equal (testSeq4 |> Seq.groupWhen isOdd |> list2) (testSeq4_groupWhen_Equal |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "does not return incorrect jagged list, case3: [3; 3; 2; 4; 2; 2]" (fun _ ->
- Expect.notEqual (testSeq4 |> Seq.groupWhen isOdd |> list2) (testSeq4_groupWhen_NotEqual |> list2) "Seq.groupWhen did not return incorrect jagged list"
+ Expect.notEqual (testSeq4 |> Seq.groupWhen isOdd |> list2) (testSeq4_groupWhen_NotEqual |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "returns correct jagged list, case4: [3; 3; 2; 4; 2; 1]" (fun _ ->
- Expect.equal (testSeq5 |> Seq.groupWhen isOdd |> list2) (testSeq5_groupWhen_Equal |> list2) "Seq.groupWhen did return correct jagged list"
+ Expect.equal (testSeq5 |> Seq.groupWhen isOdd |> list2) (testSeq5_groupWhen_Equal |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "does not return incorrect jagged list, case4: [3; 3; 2; 4; 2; 1]" (fun _ ->
- Expect.notEqual (testSeq5 |> Seq.groupWhen isOdd |> list2) (testSeq5_groupWhen_NotEqual |> list2) "Seq.groupWhen did not return incorrect jagged list"
+ Expect.notEqual (testSeq5 |> Seq.groupWhen isOdd |> list2) (testSeq5_groupWhen_NotEqual |> list2) "Seq.groupWhen did return incorrect jagged list"
)
testCase "returns correct jagged list, case4: [6; 6; 2; 4; 2; 8]" (fun _ ->
- Expect.equal (testSeq6 |> Seq.groupWhen isOdd |> list2) ([testSeq6 |> list]) "Seq.groupWhen did return correct jagged list"
+ Expect.equal (testSeq6 |> Seq.groupWhen isOdd |> list2) ([testSeq6 |> list]) "Seq.groupWhen did return incorrect jagged list"
)
testCase "does not return incorrect jagged list, case4: [6; 6; 2; 4; 2; 8]" (fun _ ->
Expect.notEqual (testSeq6 |> Seq.groupWhen isOdd |> list2) ([]) "Seq.groupWhen did not return empty (jagged) list"
)
]
+ testList "Seq.chunkBy" [
+ test "chunk integers by odd/even" {
+ Expect.equal (testSeq2 |> Seq.chunkBy isOdd |> list2Tpl) (testSeq2_chunkByIsOdd |> list2Tpl) "Seq.chunkBy did return incorrect jagged list"
+ }
+ test "chunk integers by odd/even only one chunk" {
+ Expect.equal (testSeq6 |> Seq.chunkBy isOdd |> list2Tpl) (testSeq6_chunkByIsOdd |> list2Tpl) "Seq.chunkBy did return incorrect jagged list"
+ }
+ test "chunk strings by id" {
+ Expect.equal (testSeq7 |> Seq.chunkBy id |> list2Tpl) (testSeq7_chunkById |> list2Tpl) "Seq.chunkBy did return incorrect jagged list"
+ }
+ ]
testList "Seq.intersect" [
testCase "returns correct list, case1: []" (fun _ ->
Expect.equal (Seq.intersect Seq.empty Seq.empty |> list) [] "Seq.intersect did return correct list"
diff --git a/tests/FSharpAux.IO.Tests/FSharpAux.IO.Tests.fsproj b/tests/FSharpAux.IO.Tests/FSharpAux.IO.Tests.fsproj
index 1362dc2..058c43a 100644
--- a/tests/FSharpAux.IO.Tests/FSharpAux.IO.Tests.fsproj
+++ b/tests/FSharpAux.IO.Tests/FSharpAux.IO.Tests.fsproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net8.0
false
@@ -13,9 +13,9 @@
-
-
-
+
+
+
diff --git a/tests/FSharpAux.Tests/FSharpAux.Tests.fsproj b/tests/FSharpAux.Tests/FSharpAux.Tests.fsproj
index 6c2773b..ba62721 100644
--- a/tests/FSharpAux.Tests/FSharpAux.Tests.fsproj
+++ b/tests/FSharpAux.Tests/FSharpAux.Tests.fsproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net8.0
false
@@ -17,11 +17,11 @@
-
-
-
+
+
+
-
+