Skip to content

Commit

Permalink
About Filtering
Browse files Browse the repository at this point in the history
First attempt at explaining the Filtering functions:
- filter
- find / tryFind
- choose
- pick
  • Loading branch information
xdaDaveShaw committed Feb 12, 2015
1 parent e279837 commit 0234aa7
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
121 changes: 121 additions & 0 deletions FSharpKoans/AboutFiltering.fs
@@ -0,0 +1,121 @@
namespace FSharpKoans
open FSharpKoans.Core

module NumberFilterer =

let someIfPositive x =
if x % 2 = 0 then Some x
else None

//---------------------------------------------------------------
// Getting Started with Filtering Lists
//
// Lists in F# can be filtered in a number of ways.
// This koan looks at:
// - filter
// - find / tryFind
// - choose
// - pick
//---------------------------------------------------------------

[<Koan(Sort = 22)>]
module ``about filtering`` =
open NumberFilterer

[<Koan>]
let FilteringAList() =
let names = [ "Alice"; "Bob"; "Eve"; ]

// Find all the names starting with "A" using an anonymous function
let actual_names =
names
|> List.filter (fun name -> name.StartsWith( "A" ))

AssertEquality actual_names [ __ ]

//Or passing a function to filter
let startsWithTheLetterB (s: string) =
s.StartsWith("B")

let namesBeginningWithB =
names
|> List.filter startsWithTheLetterB

AssertEquality namesBeginningWithB [ __ ]

[<Koan>]
let FindingJustOneItem() =
let names = [ "Alice"; "Bob"; "Eve"; ]
let expected_name = "Bob"

// find will return just one item, or throws an exception

let actual_name =
names
|> List.find (fun name -> name = __ )

//??? What would happen if there are 2 Bob's in the List?

AssertEquality expected_name actual_name

[<Koan>]
let FindingJustOneOrZeroItem() =
let names = [ "Alice"; "Bob"; "Eve"; ]

// tryFind returns an option so you can handle 0 rows returned
let eve =
names
|> List.tryFind (fun name -> name = "Eve" )
let zelda =
names
|> List.tryFind (fun name -> name = "Zelda" )

AssertEquality eve.IsSome __
AssertEquality zelda.IsSome __

[<Koan>]
let ChoosingItemsFromAList() =
let numbers = [ 1; 2; 3; ]

// choose takes a function that transforms the input into an option
// And filters out the results that are None.
let positiveNumbers =
numbers
|> List.choose someIfPositive

AssertEquality positiveNumbers [ __ ]

//You can also use the "id" function on types of 'a option list
//"id" will tell choose only to return just those that are "Some"
let optionNames = [ None; Some "Alice"; None; ]

let namesWithValue =
optionNames
|> List.choose id

//Notice the type of actual result is 'string list', where as optionNumbers is 'string option list'
AssertEquality namesWithValue [ __ ]

[<Koan>]
let PickingItemsFromAList() =
let numbers = [ 5..10 ]

//Pick is similar to choose, but returns the first element, or throwns an exception if are no
//items that return "Some" (a bit like find does)
let firstEvenPositive =
numbers
|> List.pick someIfPositive

AssertEquality firstEvenPositive __

//As with choose, you can also use the "id" function on types of 'a option list
//to return just those that are "Some"
let optionNames = [ None; Some "Alice"; None; Some "Bob"; ]

let firstNameWithValue =
optionNames
|> List.pick id

AssertEquality firstNameWithValue __

//There is also a tryPick which works like tryFind, returning "None" instead of throwing an exception.
1 change: 1 addition & 0 deletions FSharpKoans/FSharpKoans.fsproj
Expand Up @@ -76,6 +76,7 @@
<Compile Include="AboutDiscriminatedUnions.fs" />
<Compile Include="AboutModules.fs" />
<Compile Include="AboutClasses.fs" />
<Compile Include="AboutFiltering.fs" />
<Compile Include="PathToEnlightenment.fs" />
<None Include="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
Expand Down

0 comments on commit 0234aa7

Please sign in to comment.