Skip to content

Instantly share code, notes, and snippets.

@markusl
Created September 5, 2013 10:07
Show Gist options
  • Save markusl/6448282 to your computer and use it in GitHub Desktop.
Save markusl/6448282 to your computer and use it in GitHub Desktop.
Longest common substring, in F#.
module LongestCommonSubstring
let get (strings:seq<string>) =
let first' = strings |> Seq.tryFind (fun _ -> true)
let isWhiteSpace = System.String.IsNullOrWhiteSpace
let mapper substringLength (first:string) currentStrings offset =
if substringLength + offset < first.Length then
let currentSubstring = first.Substring(offset, substringLength)
if not(isWhiteSpace(currentSubstring)) &&
not(currentStrings |> List.exists(fun f -> f = currentSubstring)) then
currentSubstring :: currentStrings
else currentStrings
else
currentStrings
match first' with
| Some(first) ->
[first.Length - 1 .. -1 .. 0]
|> List.map(fun substringLength ->
[0 .. first.Length]
|> List.fold (mapper substringLength first) List.Empty)
|> List.concat
|> Seq.sortBy(fun s -> s)
|> Seq.sortBy(fun s -> -s.Length)
|> Seq.filter(fun s -> strings |> Seq.forall(fun c -> c.Contains(s)))
| None -> Seq.empty
let getFromStart (strings:seq<string>) =
let possibleSubStrings (str:string) =
[str.Length-1 .. -1 .. 0] |> List.map(fun i -> str.Substring(0, i))
strings
|> List.ofSeq
|> List.map possibleSubStrings
|> List.concat
|> Seq.distinct
|> Seq.filter(fun s -> strings |> Seq.forall(fun c -> c.StartsWith(s)))
module LongestCommonSubstringTest
open System
open System.Diagnostics
open FsUnit
open NUnit.Framework
[<TestFixture>]
type ``LongestCommonSubstringTest`` ()=
let strings1 = ["2sdllf4234foobar"; "34sdfsdf62634foobaz"; "2564xx65foox"; "266foof"]
let strings2 = ["foobar"; "foobaz"; "foox"; "foof"]
[<Test>]
member x.``get`` ()=
let result = LongestCommonSubstring.get strings1
result |> Seq.length |> should equal 6
result |> Seq.nth 0 |> should equal "foo"
result |> Seq.nth 1 |> should equal "fo"
result |> Seq.nth 2 |> should equal "oo"
result |> Seq.nth 3 |> should equal "2"
result |> Seq.nth 4 |> should equal "f"
result |> Seq.nth 5 |> should equal "o"
[<Test>]
member x.``getFromStart`` ()=
let result = LongestCommonSubstring.getFromStart strings2
result |> Seq.length |> should equal 4
result |> Seq.nth 0 |> should equal "foo"
result |> Seq.nth 1 |> should equal "fo"
result |> Seq.nth 2 |> should equal "f"
result |> Seq.nth 3 |> should equal String.Empty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment