A more functional way
authorUmmon <greg.burri@gmail.com>
Tue, 12 Dec 2017 12:28:45 +0000 (13:28 +0100)
committerUmmon <greg.burri@gmail.com>
Tue, 12 Dec 2017 12:28:45 +0000 (13:28 +0100)
AdventOfCode2017/Day12.fs

index 1f83f1d..34c0e46 100644 (file)
@@ -1,47 +1,27 @@
 module AdventOfCode2017.Day12
 
 open System
-open System.Linq
-open System.Collections.Generic
-
-type Graph =
-    {
-        Name : string
-        Neighbors : List<Graph>
-    }
-
-let parseInput (lines : string[]) : (Graph * string[]) list =
-    [
-        for line in lines do
-            let splitLine = line.Split ([| ' '; ',' |], StringSplitOptions.RemoveEmptyEntries)
-            yield { Name = splitLine.[0]; Neighbors = List<Graph> () }, splitLine.[2 .. splitLine.Length - 1]
-    ]
-
-let graphCount (input : (Graph * string[]) list) =
-    let toVisit = Dictionary<string, Graph> ()
-
-    for g, _ in input do
-        toVisit.Add (g.Name, g)
-
-    for g, neighbors in input do
-        for neighbor in neighbors do
-            let g' = toVisit.[neighbor]
-            g'.Neighbors.Add g
-            g.Neighbors.Add g'
-
-    let visitedGroups = List<Dictionary<string, Graph>> ()
-
-    let rec visit (g : Graph) (dic : Dictionary<string, Graph>) =
-        if dic.ContainsKey g.Name |> not then
-            toVisit.Remove g.Name |> ignore
-            dic.Add (g.Name, g)
-            for n in g.Neighbors do
-                visit n dic
-
-    while toVisit.Count > 0 do
-        let dic = Dictionary<string, Graph> ()
-        visitedGroups.Add dic
-        visit (toVisit.First().Value) dic
-
-    visitedGroups.First().Count, visitedGroups.Count
 
+let parseInput (lines : string[]) : Map<int, Set<int>> =
+    lines
+    |> Array.fold (
+        fun dic str ->
+            let l = str.Split ([| ' '; ',' |], StringSplitOptions.RemoveEmptyEntries)
+            dic.Add (int l.[0], l.[2 .. l.Length - 1] |> Array.map int |> Set.ofArray)
+    ) Map.empty
+
+let graphCount (g : Map<int, Set<int>>) =
+
+    let rec visit (current : int) (visited : Set<int>) : Set<int> =
+        if visited |> Set.contains current then
+            Set.empty
+        else
+            seq { yield g.[current]; for neighbor in g.[current] -> visit neighbor (visited |> Set.add current) } |> Set.unionMany
+
+    let rec nbRoots (vertices : Set<int>) =
+        if Set.isEmpty vertices then
+            0
+        else
+            1 + nbRoots (vertices - (visit (vertices |> Set.minElement) Set.empty))
+
+    visit 0 Set.empty |> Set.count, g |> Map.toList |> List.map fst |> Set.ofList |> nbRoots
\ No newline at end of file