I have been trying to learn F#, coming from C#, and I'm quite "happy" with my previous solutions. This one challenged me more, having to think 'functional'! I am not happy with how it looks, but here it is anyway!
My other attempts are on github. Critique is highly welcome!
I made a datastructure that mapped guards to days to minutes with type: Map<string,Map<string,bool array> which made it 'easy' (or so I though) to extract the data.
letrechandleguard(datastructure:Map<string,Map<string,bool[]>>)(arr:stringlist)=matcharrwith|head::tail->matchheadwith|Regex@"\[(\d+)-(\d\d)-(\d\d) (\d+):(\d+)\] (.+)"[year;month;day;hour;min;action]->letdate=newDateTime(year|>int,month|>int,day|>int,hour|>int,min|>int,0)letorigday=date.ToString"MM-dd"letnewdate=ifdate.Hour=0thendateelsenewDateTime(date.AddDays(1.0).Year,date.AddDays(1.0).Month,date.AddDays(1.0).Day)letnewday=newdate.ToString"MM-dd"matchactionwith|Regex@"Guard #(\d+)"[newguard]->ifdatastructure.ContainsKeynewguardthenifnot(datastructure.[newguard].ContainsKeynewday)thenletnewDs=letminutes:boolarray=Array.zeroCreate60letnewDay=ifhour="00"thenminutes.[min|>int]<-trueelseminutes.[0]<-truedatastructure.[newguard]|>Map.addnewdayminutesdatastructure|>Map.addnewguardnewDayhandlenewguardnewDstailelsehandlenewguarddatastructuretailelse// create new level in datastructure// new array of waking minutes, default to sleepletminutes:boolarray=Array.zeroCreate60// guard starts out as awakeletnewMap=Map.empty|>Map.addnewdayminutesletnewDs=datastructure|>Map.addnewguardnewMaphandlenewguardnewDstail|Regex@"wakes up"[]->// set time to awakedatastructure.[guard].[newday].[min|>int]<-truehandleguarddatastructuretail|Regex@"falls asleep"[]->// set all times before this to awakeletmaxMin=min|>intletminMin=tryArray.findIndexBack(funa->a)datastructure.[guard].[newday].[0..maxMin]with|:?KeyNotFoundExceptionasex->0foriin[minMin..maxMin-1]dodatastructure.[guard].[newday].[i]<-truehandleguarddatastructuretail|_->handleguarddatastructuretail|_->handleguarddatastructuretail|[]->// guard ends his day awakeMap.iter(fungdm->Map.iter(fundms->letminMin=tryArray.findIndexBack(funa->a)mswith|:?KeyNotFoundExceptionasex->0foriin[minMin..59]doms.[i]<-true)dm)datastructure// guard starts his day awakeMap.iter(fungdm->Map.iter(fundms->letminMin=tryArray.findIndex(funa->a)mswith|:?KeyNotFoundExceptionasex->0foriin[0..minMin]doms.[i]<-true)dm)datastructuredatastructure
Then Part 1
lettestinput="[1518-11-01 00:00] Guard #10 begins shift
[1518-11-01 00:05] falls asleep
[1518-11-01 00:25] wakes up
[1518-11-01 00:30] falls asleep
[1518-11-01 00:55] wakes up
[1518-11-01 23:58] Guard #99 begins shift
[1518-11-02 00:40] falls asleep
[1518-11-02 00:50] wakes up
[1518-11-03 00:05] Guard #10 begins shift
[1518-11-03 00:24] falls asleep
[1518-11-03 00:29] wakes up
[1518-11-04 00:02] Guard #99 begins shift
[1518-11-04 00:36] falls asleep
[1518-11-04 00:46] wakes up
[1518-11-05 00:03] Guard #99 begins shift
[1518-11-05 00:45] falls asleep
[1518-11-05 00:55] wakes up"letstopwatch=System.Diagnostics.Stopwatch.StartNew()letsplit=splittestinput|>Array.sort// (guard,day,minute) -> awakeletdatastruct=split|>Array.toList|>handle""Map.emptystopwatch.Stop()printfn"creating datastructure took %i milliseconds"stopwatch.ElapsedMillisecondsstopwatch.Restart()// find guard that is asleep mostletsleepyGuard=datastruct|>Map.map(funguardday->Map.map(fundaymins->Array.sumBy(funawake->ifawakethen0else1)mins)day)|>Map.map(funguardday->day|>Map.fold(funaccdaymins->acc+mins)0)|>Map.toList|>List.maxBy(fun(g,min)->min)|>fststopwatch.Stop()printfn"sleepiest guard is %s"sleepyGuardprintfn"\t calculation too %i milliseconds"stopwatch.ElapsedMillisecondsstopwatch.Restart()// find that guards most likely minute of being asleepletsleepyMinute=datastruct.[sleepyGuard]|>Map.map(fundaymins->Array.indexedmins)|>Map.toList|>List.map(funi->sndi)|>List.collect(funarr->Array.toListarr)|>List.groupBy(fun(index,awake)->index)|>List.map(funarr->sndarr)|>List.map(funa->List.map(funb->sndb)a)|>List.map(funa->a|>List.filter(funawake->notawake)|>List.length)|>List.indexed|>List.maxBy(fun(index,m)->m)|>fststopwatch.Stop()printfn"sleepiest minute of guard %s is %i"sleepyGuardsleepyMinuteprintfn"result of day 4 part 1 is: %i"((sleepyGuard|>int)*sleepyMinute)printfn"\t calculation took %i milliseconds"stopwatch.ElapsedMilliseconds
and Part 2
letpopular=datastruct|>Map.map(funguardday->Map.toListday|>List.mapsnd|>List.map(funi->Array.toListi|>List.indexed)|>List.concat//|> List.filter (fun (_,awake) -> not awake)|>List.groupBy(fun(i,_)->i)|>List.map(fun(i,l)->(i,(List.fold(funacc(_,awake)->ifawakethenaccelseacc+1)0l)))|>List.maxBy(fun(_,l)->l))|>Map.toList|>List.maxBy(fun(_,(_,t))->t)stopwatch.Stop()printfn"Guard %s spent minute %i asleep more than anyone: %i times"(fstpopular)(fst(sndpopular))(snd(sndpopular))printfn"result of day 4 part 2 is: %i"(((fstpopular)|>int)*(fst(sndpopular)))printfn"\t calculation took %i milliseconds"stopwatch.ElapsedMilliseconds
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
I have been trying to learn F#, coming from C#, and I'm quite "happy" with my previous solutions. This one challenged me more, having to think 'functional'! I am not happy with how it looks, but here it is anyway!
My other attempts are on github. Critique is highly welcome!
I made a datastructure that mapped guards to days to minutes with type:
Map<string,Map<string,bool array>
which made it 'easy' (or so I though) to extract the data.Then Part 1
and Part 2