Skip to content

Commit 7e86a26

Browse files
author
⚙︎ Greg
committed
added sort
1 parent ae635a0 commit 7e86a26

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
module SpiralOSS.FsShell.Testing.Command.SortTests
2+
3+
open Xunit
4+
open System.Linq
5+
open SpiralOSS.FsShell.Command.Sort
6+
7+
[<Fact>]
8+
let ``Test Sort`` () =
9+
let input = seq { "C"; "B"; "A" }
10+
let expect = seq { "A"; "B"; "C" }
11+
let actual = sort input
12+
Assert.True(expect.SequenceEqual(actual))
13+
14+
[<Fact>]
15+
let ``Test Sort Ignore Case`` () =
16+
let input = seq { "C"; "b"; "A" }
17+
let expect = seq { "A"; "b"; "C" }
18+
let actual = sort input
19+
Assert.True(expect.SequenceEqual(actual))
20+
21+
[<Fact>]
22+
let ``Test Sort Range`` () =
23+
let input = seq { "AC"; "BB"; "CA" }
24+
let expect = seq { "CA"; "BB"; "AC" }
25+
let actual = sort_k (Some 1, Some 1) input
26+
Assert.True(expect.SequenceEqual(actual))
27+
28+
[<Fact>]
29+
let ``Test Sort Range Ignore Case`` () =
30+
let input = seq { "AC"; "Bb"; "Ca" }
31+
let expect = seq { "Ca"; "Bb"; "AC" }
32+
let actual = sort_k (Some 1, Some 1) input
33+
Assert.True(expect.SequenceEqual(actual))
34+
35+
[<Fact>]
36+
let ``Test Sort Number Range`` () =
37+
let input = seq { "A31"; "B21"; "C11" }
38+
let expect = seq { "C11"; "B21"; "A31" }
39+
let actual = sort_kn (Some 1, Some 2) input
40+
Assert.True(expect.SequenceEqual(actual))
41+
42+
[<Fact>]
43+
let ``Test XSort`` () =
44+
let input = seq {
45+
[| "Val 1-3" ; "Val 2-3"; "Val 3-3" |]
46+
[| "Col 1" ; "Col 2"; "Col 3" |]
47+
[| "Val 1-2" ; "Val 2-2"; "Val 3-2" |]
48+
[| "Val 1-1" ; "Val 2-1"; "Val 3-1" |]
49+
}
50+
let expect = seq {
51+
[| "Col 1" ; "Col 2"; "Col 3" |]
52+
[| "Val 1-1" ; "Val 2-1"; "Val 3-1" |]
53+
[| "Val 1-2" ; "Val 2-2"; "Val 3-2" |]
54+
[| "Val 1-3" ; "Val 2-3"; "Val 3-3" |]
55+
}
56+
let actual = xsort [ 1 ] input
57+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
58+
Assert.True(expectRow.SequenceEqual(actualRow))
59+
60+
[<Fact>]
61+
let ``Test XSort Multiple`` () =
62+
let input = seq {
63+
[| "Val 1-3" ; "Val B" ; "Val 3" |]
64+
[| "Val 1-2" ; "Val A" ; "Val 2" |]
65+
[| "Val 1-1" ; "Val A" ; "Val 1" |]
66+
[| "Col 1" ; "Col 2"; "Col 3" |]
67+
}
68+
let expect = seq {
69+
[| "Col 1" ; "Col 2"; "Col 3" |]
70+
[| "Val 1-1" ; "Val A" ; "Val 1" |]
71+
[| "Val 1-2" ; "Val A" ; "Val 2" |]
72+
[| "Val 1-3" ; "Val B" ; "Val 3" |]
73+
}
74+
let actual = xsort [ 1; 2 ] input
75+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
76+
Assert.True(expectRow.SequenceEqual(actualRow))
77+
78+
[<Fact>]
79+
let ``Test XSort Ignore Case`` () =
80+
let input = [
81+
[| "Col 1" ; "Col 2"; "Col 3" |]
82+
[| "Val 1-1" ; "val 1-1"; "Val 3-1" |]
83+
[| "Val 1-3" ; "val 2-3"; "Val 3-3" |]
84+
[| "Val 1-2" ; "Val 2-2"; "Val 3-2" |]
85+
]
86+
let expect = [
87+
[| "Col 1" ; "Col 2"; "Col 3" |]
88+
[| "Val 1-1" ; "val 1-1"; "Val 3-1" |]
89+
[| "Val 1-2" ; "Val 2-2"; "Val 3-2" |]
90+
[| "Val 1-3" ; "val 2-3"; "Val 3-3" |]
91+
]
92+
let actual = xsort [ 1 ] input |> Seq.toList
93+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
94+
//printfn "YES:%A %A" expectRow actualRow
95+
Assert.True(expectRow.SequenceEqual(actualRow))
96+
97+
[<Fact>]
98+
let ``Test XSort Numeric`` () =
99+
let input = seq {
100+
[| "3"; "3" |]
101+
[| "4"; "4" |]
102+
[| "1"; "1" |]
103+
[| "2"; "2" |]
104+
}
105+
let expect = seq {
106+
[| "1"; "1" |]
107+
[| "2"; "2" |]
108+
[| "3"; "3" |]
109+
[| "4"; "4" |]
110+
}
111+
let actual = xsort_n [ 1 ] input
112+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
113+
Assert.True(expectRow.SequenceEqual(actualRow))
114+
115+
[<Fact>]
116+
let ``Test XSort Numeric Multiple`` () =
117+
let input = [
118+
[| "4"; "3"; "10" |]
119+
[| "4"; "4"; "10" |]
120+
[| "1"; "1"; "00" |]
121+
[| "4"; "4"; "20" |]
122+
[| "2"; "1"; "10" |]
123+
[| "3"; "1"; "20" |]
124+
[| "4"; "2"; "00" |]
125+
]
126+
let expect = [
127+
[| "1"; "1"; "00" |]
128+
[| "2"; "1"; "10" |]
129+
[| "3"; "1"; "20" |]
130+
[| "4"; "2"; "00" |]
131+
[| "4"; "3"; "10" |]
132+
[| "4"; "4"; "10" |]
133+
[| "4"; "4"; "20" |]
134+
]
135+
let actual = xsort_n [ 1; 2 ] input |> Seq.toArray
136+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
137+
Assert.True(expectRow.SequenceEqual(actualRow))
138+
139+
[<Fact>]
140+
let ``Test XSort Mixed`` () =
141+
let input = [
142+
[| "4"; "C"; "10" |]
143+
[| "4"; "D"; "10" |]
144+
[| "1"; "A"; "00" |]
145+
[| "4"; "D"; "20" |]
146+
[| "2"; "A"; "10" |]
147+
[| "3"; "A"; "20" |]
148+
[| "4"; "B"; "00" |]
149+
]
150+
let expect = [
151+
[| "1"; "A"; "00" |]
152+
[| "2"; "A"; "10" |]
153+
[| "3"; "A"; "20" |]
154+
[| "4"; "B"; "00" |]
155+
[| "4"; "C"; "10" |]
156+
[| "4"; "D"; "10" |]
157+
[| "4"; "D"; "20" |]
158+
]
159+
let actual = xsort' [ (1, String); (2, Numeric) ] input |> Seq.toArray
160+
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
161+
Assert.True(expectRow.SequenceEqual(actualRow))

src/FsShell.Testing/FsShell.Testing.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<Compile Include="Command/MkdirTests.fs" />
2525
<Compile Include="Command/MoveTests.fs" />
2626
<Compile Include="Command/OutputTests.fs" />
27+
<Compile Include="Command/SortTests.fs" />
2728
<Compile Include="Command/TailTests.fs" />
2829
<Compile Include="Command/TeeTests.fs" />
2930
<Compile Include="Program.fs" />

src/FsShell/Command/Sort.fs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module SpiralOSS.FsShell.Command.Sort
2+
3+
open SpiralOSS.FsShell.Infrastructure.Utility
4+
open System.Linq
5+
6+
let sort (contents:string seq) = seq { yield! contents.OrderBy(fun it -> it) }
7+
8+
let sort_k (ranges:(int option*int option)) (contents:string seq) =
9+
seq { yield! contents.OrderBy (fun content -> (stringSplice [ ranges ] content) |> String.concat "") }
10+
11+
let sort_kn (ranges:(int option*int option)) (contents:string seq) =
12+
contents |> Seq.sortBy (fun content ->
13+
let sortNum = stringSplice [ ranges ] content |> String.concat ""
14+
let (success, number) = System.Int64.TryParse(sortNum)
15+
if success then number else 0L
16+
)
17+
18+
type SortBy =
19+
| String
20+
| Numeric
21+
22+
module private Utility =
23+
let rec xSortThenBy (thenBy:(int*SortBy)->string array->'a when 'a : comparison) (retSeq:IOrderedEnumerable<string array>) (columnIndices:(int*SortBy) list) (contents:string[] seq) =
24+
match columnIndices with
25+
| [] -> retSeq
26+
| sortBy::sortBys -> xSortThenBy thenBy (retSeq.ThenBy(thenBy sortBy)) sortBys contents
27+
let inline stringSort (index,_) (content:string array) =
28+
content[index] :> System.IComparable
29+
let inline numericSort (index,_) (content:string array) =
30+
let (success, number) = System.Int64.TryParse(content[index])
31+
(if success then number else 0L) :> System.IComparable
32+
let inline eitherSort (index, sortType) (content:string array) =
33+
match sortType with
34+
| String -> stringSort (index, sortType) content
35+
| Numeric -> numericSort (index, sortType) content
36+
37+
let orderBy (contents:string[] seq) = (contents.OrderBy(fun _ -> 0))
38+
39+
let xsort (columnIndices:int list) (contents:string[] seq) =
40+
seq { yield! Utility.xSortThenBy Utility.stringSort (contents.OrderBy(fun _ -> 0)) (columnIndices |> List.map (fun it -> (it, String))) contents }
41+
42+
let xsort_n (columnIndices:int list) (contents:string[] seq) =
43+
seq { yield! Utility.xSortThenBy Utility.numericSort (contents.OrderBy(fun _ -> 0)) (columnIndices |> List.map (fun it -> (it, Numeric))) contents }
44+
45+
let xsort' (columnIndices:(int*SortBy) list) (contents:string[] seq) =
46+
seq { yield! Utility.xSortThenBy Utility.eitherSort (contents.OrderBy(fun _ -> 0)) columnIndices contents }

src/FsShell/FsShell.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@ let inline tail_n (count:int) (contents:'a seq) = Command.Tail.tail count conten
150150
let inline tail (contents:'a seq) = tail_n 10 contents
151151

152152

153+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting","")>]
154+
let inline sort (contents:string seq) = Command.Sort.sort contents
155+
156+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting by a substring","")>]
157+
let inline sort_k (range:(int option*int option)) (contents:string seq) = Command.Sort.sort_k range contents
158+
159+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting by a substring as a number","")>]
160+
let inline sort_kn (range:(int option*int option)) (contents:string seq) = Command.Sort.sort_kn range contents
161+
162+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting by columns","")>]
163+
let inline xsort (columns:int list) (contents:string[] seq) = Command.Sort.xsort columns contents
164+
165+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting by columns, each as a number","")>]
166+
let inline xsort_n (columns:int list) (contents:string[] seq) = Command.Sort.xsort_n columns contents
167+
168+
[<ManualEntry([|"sort"|],"Data Manipulation","Sorting by columns, specify as string or number","")>]
169+
let inline xsort2 (sortBy:(int*Command.Sort.SortBy) list) (contents:string[] seq) = Command.Sort.xsort' sortBy contents
170+
171+
153172
let private manualEntries = ManualEntryAttribute.getManualEntriesFromType typeof<IFsShell>
154173
[<ManualEntry([|"man";"manual"|],"Miscellaneous","This","")>]
155174
let man (funcName:string) =

src/FsShell/FsShell.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<Compile Include="Command/Move.fs" />
3232
<Compile Include="Command/Output.fs" />
3333
<Compile Include="Command/Pwd.fs" />
34+
<Compile Include="Command/Sort.fs" />
3435
<Compile Include="Command/Tail.fs" />
3536
<Compile Include="Command/Tee.fs" />
3637
<Compile Include="FsShell.fs" />

0 commit comments

Comments
 (0)