Advent of Code Day 12 Solved in C# and F#
December 14. 2015 Posted in:
Day 12’s Advent of Code challenge involved navigating through a huge JSON object and adding up all the numeric values. You could actually ‘cheat’ for part a by just using a regex, but for part b, we need to dig out the Newtonsoft.Json library and do some recursion. Here’s me describing my solutions:
So here’s the part a solution with Regex in C#
Regex.Matches(
File.ReadAllText("day12.txt"),
@"[\-0-9]+")
.Cast<Match>()
.Select(m => m.Value)
.Select(int.Parse)
.Sum()
And part b, using Newtonsoft.Json, and an extension method:
void Main()
{
var json = File.ReadAllText("day12.txt");
var o = JObject.Parse(json);
SumTokens(o).Dump(); // 65402
}
long SumTokens(JToken token)
{
if (token is JObject)
{
var jo = (JObject)token;
if (jo.IsRed()) return 0;
return jo.Properties().Select(p => p.Value).Sum(jt => SumTokens(jt));
}
else if (token is JArray)
{
var ja = (JArray)token;
return ja.Sum(jt => SumTokens(jt));
}
else if (token is JValue)
{
var jv = (JValue)token;
return (jv.Value is long) ? (long)jv.Value : 0;
}
token.Dump();
throw new InvalidOperationException();
}
static class MyExtensions
{
public static bool IsRed(this JObject jobject)
{
return jobject.Properties()
.Select(p => p.Value).OfType<JValue>()
.Select(j => j.Value).OfType<string>()
.Any(j => j == "red");
}
}
Finally, once again I’ve been trying to improve my F# skills and today I made use of pattern matching on object type with the :?
operator, as well as casting with the :?>
operator.
let json = File.ReadAllText("day12.txt")
let o = JObject.Parse(json)
let shouldAvoid avoid (jo:JObject) =
jo.Properties() |> Seq.exists (fun p -> match p.Value with | :? JValue as jv -> jv.Value = avoid | _ -> false)
let rec getSum avoid (token:JToken) =
match token with
| :? JObject as jo ->
if shouldAvoid avoid jo then 0L
else jo.Properties() |> Seq.map (fun p -> p.Value) |> Seq.map (getSum avoid) |> Seq.sum
| :? JArray as ja -> ja |> Seq.cast<JToken> |> Seq.map (getSum avoid) |> Seq.sum
| :? JValue as jv -> if jv.Type = JTokenType.Integer then jv.Value :?> int64 else 0L
| _ -> failwith (sprintf "unknown token %A" (token.GetType()) )
getSum null o |> printfn "a: %d" // 111754
getSum "red" o |> printfn "b: %d" // 65402
Want to learn more about LINQ? Be sure to check out my Pluralsight course LINQ Best Practices.