Inlägg
Hmm förutom spel så håller jag på med machine learning kurser, så jag skulle inte ha något emot ett 3080 kort med 20 GB minne. Får CUDA Out of Memory error på massa exempel. Men kort med mycket och snabbt minne verkar ju vara dom mest attraktiva mining korten som ni säger, så man får väl köra mindre batch sizes och rulla tummarna lite mer. Eller bita ihop och betala för ett 3090 kort.
Eventuell mining-reducerande åtgärder borde väl inte påverka ML väl? Som jag förstått det är det mest hashning som stryps, och ML är ju nästan enbart (matris) multiplikationer?
Dag 16, Scala. Jag tar det lite lugnare nu och koncentrerar mig på att lära mig saker och få till bra lösningar. Den här blev ok tyckte jag, nöjd med "uniques" lösningen.
object Day16 {
type Ticket = List[Int]
case class Field(name: String, ranges: Array[Range.Inclusive]) {
def matches(x: Int): Boolean = ranges.exists(_.contains(x))
def matches(l: Seq[Int]): Boolean = l.forall(matches)
}
def toField(in: String) = {
val Array(name, rs) = in.split(": ")
val ranges = rs.split(" or ").map(s => s.split("-") match
{ case Array(h, t) => Range.inclusive(h.toInt, t.toInt) })
Field(name, ranges)
}
class Categorizer(in: String) {
val Array(fds, my, ticks) = in.split("\\n\\n").map(_.split("\\n"))
val tickets: List[Ticket] = ticks.drop(1).map(_.split(",").map(_.toInt).toList).toList
val myTicket = my.last.split(",").map(_.toInt).toList
val fields = fds.map(toField).toList
def included(in: Int, ranges: Seq[Range.Inclusive]) = {
!ranges.forall(!_.contains(in))
}
def validTickets = {
val ranges = fields.flatMap(_.ranges)
tickets.filter(_.forall(i => included(i, ranges)))
}
def possibleCategories: List[List[Field]] = validTickets.transpose.map(column => fields.filter(_.matches(column)))
def uniques[A](in: List[List[A]]): List[A] = {
for {
l <- in
l2 <- in
if l.size - l2.size == 1
} yield l.diff(l2).head
}
def uppg1: Int = tickets.flatten.filter(!included(_, fields.flatMap(_.ranges))).sum
def uppg2: BigInt = {
val departureIndexes = uniques(possibleCategories).zipWithIndex.filter(_._1.name.startsWith("departure")).map(_._2)
departureIndexes.map(myTicket(_)).foldLeft(BigInt(1))(_ * _)
}
}
Tack för länken. Har tjuvkikat på en del andra lösningar idag, och sett att de flesta använder någon variant av denna. Att implementera den är trivialt, men jag förstår ärligt talat fortfarande inte intuitivt hur och varför det fungerar....
Om du går längst en stig och vet att det finns två olika vägar att hitta till punkten du är nu. Du ser tre andra vägar framåt, du går till den första, där har någon skrivit "det finns 5 olika sätt att hitta hit" på en lapp, du stryker 5 och skriver 7 istället, och gör så på alla tre vägarna. Finns det ingen lapp på någon av dom resterande så får du skriva en ny med "finns 2 olika sätt" på och lägga dit. När du gått genom alla vägar så kollar du lappen i Rom (eftersom alla vägar leder till Rom) för att se alla möjliga vägar dit.
hur hade man då löst det?
Kollegas förklaring på hans eleganta lösning:
Jahapp, uppgift 1 löste jag på under 10 minuter och med en oneliner så kände mig väldigt mallig, men har kört fast helt på uppgift 2, även efter att jag gav upp och tittade på andras lösningar. Hilfe?
Edit: Never mind, hittade buggen.
Ger rätt på exempelinput (exvis 19208), och är snabb. Men ger för högt värde på riktiga input enligt AoC. But why?
def paths(in: List[Int]) = {
in.tails.filter(!_.isEmpty).foldLeft(Map[Int, BigInt](0 -> BigInt(1))) {
case (map, head::tail) => {
val validAdapters: List[Int] = tail.takeWhile((x) => x - head < 4)
val currentPaths: BigInt = map.get(head).get
validAdapters.foldLeft(map) { (nmap, elem) => nmap.updated(elem, currentPaths + nmap.get(elem).getOrElse(BigInt(0)) ) }
}
}.get(in.last)
}
// Uppgift 1
input.foldLeft((0,0,0)) { case ((last, ones, threes), x) => if (x-last == 3) (x, ones, threes+1) else if (x-last == 1) (x, ones + 1, threes) else (x, ones, threes) }
Felet: Jag hade gjort en import scala.collection.mutable._ i min REPL när jag satt och labbade, så någonstans refererade jag till en mutable Map, eller det blev en implicit conversion eller något. Startade jag om min REPL och pastade koden ovan funkade det.
Jag hade helt glömt bort AoC i år. Gick tillbaka och löste några av de kortare problemen också.
Kul med någon annan som kör Scala också! Se där, dag 9 uppgift 1 gick att lösa funktionellt också, misstänkte det men gav upp.
Inte lika snabb som Go, inte lika snygg som Python, men jag löste det i alla fall. Dag 9, Scala.
object Xmas extends App {
def apply(l: List[BigInt]) = new Xmas(l)
//Uppgift 1
def findNonValid(in: List[BigInt], preambleSize: Int):Option[BigInt] = {
val candidates = in.drop(preambleSize)
candidates.foldLeft(Xmas(in.take(preambleSize))) { (acc, elem) => acc.add(elem) }.nonvalids.headOption
}
//Uppgift 2
def find(list: List[BigInt], wanted: BigInt): Option[BigInt] = {
for {
x <- 0 to list.size
y <- x to list.size
if (y - x > 1)
slice = list.slice(x,y)
if (slice.sum == wanted)
} return Some(slice.min + slice.max)
None
}
class Xmas(val preamble: List[BigInt]) {
import scala.collection.mutable
val nonvalids = new mutable.Queue[BigInt]()
val source = new mutable.Queue().addAll(preamble)
def valids = (for { x <- source; y <- source; if x!=y } yield (x + y)).distinct
def add(x: BigInt): Xmas = {
if (source.contains(x) || !valids.contains(x)) nonvalids.addOne(x)
else source.addOne(x).dequeue()
this
}
}
}
Uppgift 2 försökte jag först skapa alla permutations rekursivt med immutables och sen köra fold, out of memory inte så oväntat. Sen försökte jag en rekursiv med head/tail pekare, avbröt den efter 5 minuter (kan ha funnits en bugg). Denna lösning kör på lite under en sekund vilket ändå är rätt kasst jämfört med Flexberts 16μs, ska fundera hur jag kan optimera både snygghet och hastighet. Efter att jag hunnit igenom nästa ML kapitel i boken.
Edit: Kunde ju inte släppa det här. Nytt försök på tvåan:
def find(list: List[BigInt], wanted: BigInt): Option[BigInt] = {
for {
x <- 1 to list.size
slice <- list.sliding(x)
if (slice.sum == wanted)
} return Some(slice.min + slice.max)
None
}
Nu körde den på 8 mllisecs. Ett par orders of magnitude snabbare än tidigare. Forfarande 3 orders of magnitude långsammare än Go, men det får duga för icke-kompilerad, icke-jittad kod som körs i en REPL.
Dag 8 Scala. Uuugh. Satt över 4 timmar idag. Tänkte "bra, nu kan jag ta en promenad och få lite sol kanske för att rensa huvudet och bli lite gladare". Tittar ut, det är "molnig vinterdag under pandemiåret 2020 regisserad av Ingmar Bergman".
object Emulator extends App {
sealed trait Errors
case class InfiniteRecursion(line: Int) extends Errors
case class OobAttempt(line: Int) extends Errors
sealed trait Ops
case class Nop(steps: Int) extends Ops
case class Jmp(steps: Int) extends Ops
case class Acc(value: Int) extends Ops
def apply(program: List[String]) = new Emulator(program)
def decode(str: String):Ops = (str.take(3), str.drop(4).toInt) match {
case ("nop", amount) => Nop(amount)
case ("acc", amount) => Acc(amount)
case ("jmp", step) => Jmp(step)
case _ => throw new IllegalArgumentException(s"Unknown op $str")
}
class Emulator(val program: List[String]) {
def step(seen: Set[Int], acc:Int, pos:Int, fixed: Boolean = false):Either[Errors, Int] = {
if (seen.contains(pos)) return Left(InfiniteRecursion(pos))
if (pos < 0 || pos > program.size-1) return Left(OobAttempt(pos))
val op = decode(program(pos))
val newValue = op match {
case Acc(value) => acc + value
case _=> acc
}
//Horray, the program terminated and we have an answer
if (pos==program.size-1) return Right(newValue)
val newPos = op match {
case Jmp(steps) => pos + steps
case _ => pos + 1
}
val newSeen = seen + pos
def result = step(newSeen, newValue, newPos, fixed)
(fixed, result, op) match {
case (_, Right(answer), _) => result //we have an answer, return it
case (true, Left(err), _) => result //Already tried fixing once, not allowed more attempts.
case (false, Left(err), Nop(x)) => step(newSeen, acc, pos + x, true) //Change to Jmp
case (false, Left(err), Jmp(_)) => step(newSeen, acc, pos+1, true) //Change to Nop
case (false, Left(err), _) => result //Accs are never wrong, nothing to do here.
}
}
def run(): Either[Errors, Int] = {
step(Set[Int](), 0, 0)
}
}
}
Blev väl acceptabel tillslut, men "step" är för lång, den gör return på 8 olika ställen, och är svår att testa på något utom full programinput. Känns inte som det blev så funktionellt denna gång.
Dag: 7
Språk: VB.Net
Som Ruby programmerare (bland annat) så måste jag säga att VB.Net är behagligt läsbart. När man börjat vänja sig vid språk som inte har brackets i olika former och semikolon överallt så sticker dom i ögonen när man kommer tillbaka till språk (C och alla dess barn exvis) som kräver dom.
Dag 7. Läs inte om du vill lösa uppgiften helt på egen hand. Jag behöver hjälp.
> Är det meningen att man ska loopa mer än två gånger? I så fall hur vet man när man kan sluta loopa?
Jag löste båda rekursivt (metoder som anropar sig själva med nya parametrar). Har en kollega som löste det på ett annat sätt för han gillar inte rekursion (tycker det är krångligt) så det går uppenbarligen, typ med en while-loop och muterbara datastrukturer kan jag tänka. Men så här löste jag dom (i pseudokod).
Uppgift 1: Parsa filen så du får en Map(String -> List[String]). Vi struntar i siffrorna i uppgift 1, så det blir exvis
"blå" -> ["vit", "röd", "guld"]
"svart" -> ["blå"]
"vit" -> []
Skapa en metod "sökaren" som tar emot två Stränglistor: attUndersöka och hittade.
define sökaren(attUndersöka, hittade):
IF attUndersöka listan är tom
RETURN "hittade" listan parametern precis som vi fick in den. Nu är vi klara, kallas basfallet i rekursion)
ELSE plocka ut ett element "x" från attUndersöka så attUndersöka är ett element mindre.
lägg "x" i listan över hittade
gå igenom datastrukturen och hitta dom alla dom rader där listorna innehåller "x".
lägg till nycklarna som pekar på dom listorna till listan attUndersöka OM dom inte redan finns där
RETURN sökaren(nyaAttUndersöka, nyaHittade)
Så anropar du sökaren med Listan ["guld"] och tom lista, eftersom det är guld vi vill undersöka, och vi har inte hittat något än.
Första varvet: attUndersöka är inte tom. Så vi plockar ur "guld", och hittar att blåa väskor innehåller guldväskor. Vi anropar sökaren med Listorna ["blå"] respektive ["guld"] och returnerar vad det varvet returnerar
Andra varvet: attUndersöka är inte tom. Ta ut "blå", hitta "svart". Anropa sökaren med ["svart"] respektive ["guld", "blå"] och returnerar du vet vad.
Tredje varvet: attUndersöka är inte tom. Ta ut svart, hitta inget. Anropa sökaren med tom lista och ["guld", "blå", "svart"]
Fjärde varvet: attUndersöka är tom, vi returnerar hittade: ["guld", "blå", "svart"] och det poppar upp och blir slutgiltiga svaret. Längden på "hittade" minus ett (för vi skiter i "guld", vi ville bara ha hur många möjliga yttre väskor den har) är svaret.
Uppgift 2:
Kolla på min kod ovan och se om du förstår, jag orkar inte skriva en så lång förklaring igen.
#18791461
Men allt fram till totalWeight läser och parsar bara filen till en Map så som jag vill ha den, den här gången måste vi bry oss om siffrorna i texten också. Så själva körningen är totalWeight som anropar sig själv tills den är klar efter att jag anropat den första gången. Men istället för en "hittade" lista så returnerar den rekursivt vad varje väska innehåller (gånger antal av den typen).
GLaDER hade en rätt tydlig förklaring på uppgift 2 också tyckte jag.
Inte nöjd med dagens insats eller lösning. Först stötte jag på en bugg, när jag körde ScalaTest med "sbt test" så kastade allt användande av regex matchers en Java nullpointer exception oavsätt input. Men körde jag det som ett standalone program eller via Ammonite REPL funkade identisk kod klockrent. Förmodligen någon versionskonflikt av senaste versionerna av OpenJDK Java + Scala + sbt + ScalaTest som orsakar. Orkar jag gräva i det och submitta en buggrapport eller en eventuell open source fix...?
Sen slösade jag jättemycket tid på
att försöka bygga upp en weighted graph med fold till en custom Tree klass, ville triumfera med snygg oneliner igen. Men blev soppa av allt, särskilt som jag inte kunde skriva unit tester. Och tiden drog iväg så slutade med att jag gjorde rekursiv lookup på map. Känns hackigt, men tröstar mig med att Ingetledigtnamn är inne på liknande spår. Och att när jag tänker efter så är det ju en utmärkt weighted graph struktur som jag gjorde med min Map, så behöver inte skriva någon egen klass. Jag behövde bara komma på hur man traverserade den rätt.
val BAG_MATCHER = " ?(\\d+) (.*) bag.*".r
case class Bag(weight: Int, color: String)
def contentToList(s: String): List[Bag] = {
s.split(",").toList.flatMap {
case BAG_MATCHER(number, color) => List(Bag(number.toInt, color))
case default => List() // "no other bags" och ev andra strängar = tom väska
}
}
def lineToTuple(s: String): Tuple2[String, List[Bag]] = {
val color::content = s.split("bags contain ").map(_.trim).toList
(color, contentToList(content.last))
}
val bags = (read.lines! pwd/"input.txt").map(lineToTuple).toMap
def totalWeight(color: String): Int = {
bags(color) match {
case List() => 1
case list => (list.map { bag => bag.weight * totalWeight(bag.color) }.sum) + 1
}
}
totalWeight("shiny gold") - 1
Ugh, nu börjar det kännas som att awk har gjort sitt för i år.
Ändå fascinerad hur mycket du lyckats lösa på det spåret, och imponerad av hur snyggt det ofta blev. Snyggt jobbat!
Tror nästan jag måste byta språk. Att döma av lösningarna jag sett i dag är det ganska många som kör set-baserade lösningar och då blir det ganska enkelt, men detta slår rekord.
Kul att frälsa folk till mitt favoritspråk, men du har ju map, filter, reduce och dom andra på collections i Python också, så tror nog att du kan få till något liknande.
Dag 6, Python one-liner + Python, inte fullt så komplex och med kommentarer.
Just ja, unions och intersections är bra. En ännu mindre lösning för dag 6 uppgift 2 i Scala, inspirerad av din lösning:
val groups = (read! pwd/"input.txt").split("\\n\\n").map(_.split("\\s+")
groups.map(_.reduce(_ intersect _).size).sum
Irriterad på att jag inte kommer på hur man får en referens till instansmetoder i Scala utan att ha en instans. I Kotlin eller Java 8 och framåt skulle det varit exvis "String::intersect" (Edit: som Dave1080 visar snyggt exempel på nedan.)
Lösningsförklaring: reduce tar en binär funktion som appliceras på alla element i en collection parvis tills du har ett element kvar istället för en collection. Så jag gjorde en lite kryptisk shorthand motsvarande typ
List("abc", "ab", "ac").reduce { (firstString, secondString) => firstString.intersect(secondString) } // Returnerar strängen "a"
val intersectioncounts = intersectionStrings.map( (str) => str.size)
val finalAnswer = intersectioncounts.sum // "sum" finns fördefinerad på numeric collections som collection.reduce { (x,y) => x + y }
Dag 6 Scala:
import ammonite.ops._
val groups = (read! pwd/"input.txt").split("\\n\\n").map(_.split("\\s+")
groups.map(_.flatten.distinct.size).sum //Uppgift 1
groups.map{ (group) => group.flatten.groupBy(identity).count { case(_k,v) => v.size == group.size }}.sum //Uppgift 2
Eller om jag skulle skriva lite mer maintainable kod som jag inte skulle vilja slå ihjäl mig själv om jag kom tillbaka till för att fixa en bugg i en vecka senare. Inklusive kommentarer för dom som inte kan Scala:
def count(group: Array[String]): Int = {
//För input Array("ab", "ac") gör jag flatten så vi får Array('a','b','a','c')
//groupBy omvandlar till Map och funktionen vi skickar in berättar hur man väljer nyckel.
// "identity" är inbyggd, det är (x) => x funktionen.
//Så nu får vi exvis: Map('a' -> Array('a', 'a'), 'b' -> Array('b'), 'c' -> Array('c'))
val map:Map[Char,Array[Char]] = group.flatten.groupBy(identity)
//Räkna hur många entries som alla svarat på, exvis Map('a' -> Array('a', 'a')
map.count { case(_key, valueArray) => valueArray.size == group.size }
}
}
//Mappa så vi omvandlar vår Array från att innehålla Arrays av String till att vara en Array of Int. Summera innehållet i Arrayen.
groups.map(count).sum
Kom på att en sak som kan vara lite förvirrande är att jag använder lite olika sätt att referera till funktioner. I Scala kan man för exvis map skriva:
val l = List("hej", "hopp") //variabeln l är List[String] men det behöver jag inte skriva, det infereras.
l.map( (s: String) => s.size) //Ger oss List(3, 4). Detta kan även skrivas som:
l.map(_.size) //Underscore placeholder shortcut, Scala vet att det är en List[String] så kan använda String metoder på _
//Eller om vi har en funktionsreferens kan vi skicka in den direkt till map, Scala matchar in parametrarna och deras typer.
//Identity finns i PreDef så den är alltid tillgänglig: https://www.scala-lang.org/api/current/scala/Predef$.html#ide...
l.map(identity) //Returnerar List("hej", "hopp") inte oväntat.
//Och om man vill pattern matcha på tupler - det här slet jag länge med innan jag hittade rätt lösning
//första gången. Blir enkel kod men lite komplicerad typteori under.
val tuples = List(("foo",1),("bar", 2))
tuples.map ( (a,b) => ..) //detta kompilerar inte, map metoden kräver alltid en funktion som tar en parameter, inte två.
tuples.map { (a) =>
val stringPart = a._1 //Enda stället med one-based indexing i språket. Mycket irriterande.
val intPart = a._2
} //Kompilerar, men känns pratigt.
//Pattern matching to the rescue. Nu slipper vi se 1-indexing också.
//Det innanför måsvingarna omvandlas till en PartialFunction[A,B] som alltså matchar parametern som behövs för map.
tuples.map { case(stringPart, intPart) => ... }
Hur noggrann tycker ni man ska vara? Tänker typ på första dagen om listan skulle varit ett element som var 1010 så borde detta felhanteras, men det krävs inte för att lösa uppgiften.
Det är ju inte produktionskod som måste framtidssäkras direkt, du har kompletta listan med input just nu.
Men som en heads-up så har jag hört från kollegor som kört det här tidigare att det mot slutet av kalendern ofta kommer uppgifter som bygger på varandra, exvis att man först får att man ska skriva en op decoder, och sen ska byggs det vidare på den efterföljande dagar tills man tillslut har en grundläggande CPU emulator. Så det kan vara värt att få igång vanan att skriva ordentliga unit-tester så man kan fånga eventuella edge cases.
En kollega fastnade ordentligt på dag x+5 och slet hela helgen med felsökning för han trodde han hade bugg i den dagens kod, och så var det en bugg i op-decodern som han skrev dag x, som inte detekterades med tävlingsinput från den dagen...
Edit: Men om det hade varit produktionskod så absolut, även för dag 1, man vet aldrig vad för skräp man får in även från klienter som säger sig följa en standard. Ibland är det till och med deras egen standard som dom inte följer! En bra tumregel för publika APIer är "be liberal in what you accept and conservative in what you send". Jag tolkar det som att programmera defensivt mot all input du inte kontrollerar, men kasta inte exception för minsta fel. Men däremot när du retunerar värden eller själv anropar andra, se till att följa standarder till punkt och pricka.
Dag 5, Python.
Hade varit lätt att göra en enradare av denna genom att om man gick igenom listan två gånger, men det tog emot. Så idag blev det två uttryck. För en van Python-programmerare skulle jag nog säga att det är lätt att förstå vad som görs.
seats = [int(line.translate({70:48,66:49,82:49,76:48}), 2)
for line in open("input")]
print(max(seats), *[i + 1
for i in range(128 * 8)
if i in seats and i + 1 not in seats and i + 2 in seats])
Kört lite Python tidigare men fick titta ett tag innan jag förstod.
Translate gör strängen till binary, int parsar med base 2 så du direkt får stolsnumret?
Snygg lösning.
Nu känns min lösning tafflig i jämförelse, men det var kul att skriva lite rekursion.
Scala dag 5:
def reducer(s: String, range: List[Int], low: Char, high: Char): Int = {
if (s.isEmpty)
range.head
else {
val reducedRange = s.head match {
case `high` => range.takeRight(range.size/2)
case `low` => range.take(range.size/2)
}
reducer(s.tail, reducedRange, low, high)
}
}
def row(s: String): Int = reducer(s.take(7), (0 to 127).toList, 'F', 'B')
def columns(s: String): Int = reducer(s.drop(7), (0 to 7).toList, 'L', 'R')
def seat(s: String) = row(s) * 8 + column(s)
import ammonite.ops._ //Syntaktiskt socker för filläsning
val seats = (read.lines! pwd/"input.txt").map(seat)
// Uppgift 1
seats.max
//Uppgift 2
val all = (seats.min+1 to seats.max-1).toList
all.diff seats
Edit: Jag var tvungen att se hur mycket jag kunde Pythonifera Scala koden.
import ammonite.ops._ //Syntaktiskt socker för filläsning
def toSeat(s: String) = Integer.parseInt(s.map { case 'F' => '0'; case 'B' => '1'; case 'L' => '0'; case 'R' => '1' }, 2)
val seats = (read.lines! pwd/"input.txt").map(toSeat)
(seats.min+1 to seats.max-1).toList diff seats
Älskar språk med stark pattern matching, Elixir, Kotlin och TypeScript kan göra liknande vet jag, TS till och med matcha på strukturella typer vilket är snyggt. Jag tror nyaste Java versionen har matchining liknande Scala/Kotlin? Om inte så är det på väg.
Dag 4 i Scala:
// Skapa regexes. Kunde gjort regex inline i Scala match-clausen, men regex Pattern instanser kompileras
// på JVMen till Matchers. Så Matchers blir snabba, men kompileringen är en dyr operation och tvivlar
// på att kompilatorn har en regel för att kolla om regex strängen är statisk och isf hoistar ut och bara
// kompilerar en gång.
val DIG_4 = "(\\d{4})".r
val CM = "(\\d+)cm".r
val IN = "(\\d+)in".r
// Filteringsfunktionen. Eftersom regexarna har match group i sig så kan jag assigna en variabel
// (exvis birthYear) till match groupen och sen använda variabeln i case kropparna.
// Är inte konsekvent, använder in-line regex på dom 3 sista, skulle kunna gjort dom statiska som dom
// ovan och även använt dom i case matchen och sen bara returnera "true" i kroppen men tyckte det blev
// mer läsbart så här. Om det var riktig produktionskod med kritisk performance skulle jag gjort val Patterns
// utanför funktionen här med.
def validator(s: String): Boolean = {
s.split(":") match {
case Array("byr", DIG_4(birthYear)) => (1920 to 2002 contains birthYear.toInt)
case Array("iyr", DIG_4(issueYear)) => (2010 to 2020 contains issueYear.toInt)
case Array("eyr", DIG_4(expireYear)) => (2020 to 2030 contains expireYear.toInt)
case Array("hgt", CM(height)) => (150 to 193 contains height.toInt)
case Array("hgt", IN(height)) => (59 to 76 contains height.toInt)
case Array("hcl", color) => color.matches("^\\#((\\d|[a-f]){6})")
case Array("ecl", eye) => eye.matches("(amb)|(blu)|(brn)|(gry)|(grn)|(hzl)|(oth)")
case Array("pid", pid) => pid.matches("\\d{9}")
case _ => false
}
}
val passports = inputFile.split("\\n\\n")
//Tokenisera och validera
val validValues = testPassports.map(_.split("\\s+").filter(validator)
//Inte kollat om det finns duplicate keys i några passports, men för att vara säker
validValues.map(a => a.distinctBy(_.take(3))).filter(_.size == 7).size
Jag dock borde ha castat till int först och sen gjort (if x < foo && x > bar) också så det blev typsäkert även om det blir mera svårläst. Slösade en halvtimme på att jag först missat att skriva birthYear.toInt så det blev bara (1920 to 2002 contains birthYear) och en sträng kan ju aldrig finnas i en Int range så då blev ju inget passport giltigt. Hade jag använt den mer typsäkra varianten hade den kastat exception "no operator '<' on String" om jag missat att skriva toInt så då hade jag hittat buggen direkt. Alternativt hade jag kunnat skriva unit tester men jag är alltid så noga med det i produktionskod så det känns befriande att slarva lite för en gångs skull
Någon annan här som tar tillfället i akt att lära sig lite Haskell?
Dag 1:
Läser helt enkelt in talen i en lista "nums" och skriver ut produkten av paret som summerar till 2020 genom
print $ head [x*y | x <- nums, y <- nums, x+y==2020]
Måste använda "head" eftersom man ju hittar två par, y+x och x+y
Motsvarande för task 2 blir
print $ head [x*y*z | x <- nums, y <- nums, z <- nums, x+y+z==2020]
Snyggt! Jag kör Scala. Haskell ligger på min todo lista, men det är en diger lista. Kanske bara tillfället i akt att lära mig Cats, ett categori-teori baserat library för ren funktionell programmering. Ganska Hanskell-inspirarerat misstänker jag.
https://typelevel.org/cats/
Min dag 1 task 2 blev likartad, typ
(for {
x <- nums
y <- nums
z <- nums
if (x+y+z == 2020)
} yield (Bigint(x) * BigInt(y) * BigInt(z))).head
Dag 4 blev visst regex repetitionsdagen.
- Köp Samsungs 114 tums TV – få en till på köpet47
- PizzaClockers - pizzans hemligheter!1409
- Gamingdator, 15-20k4
- Asus ville ha 30 000 för trasig kontakt på 40902
- Tråden om PlayStation 514661
- Tråden om Xbox Series X|S7567
- Fundering kring Samsung tv och surroundsystem2
- Apple ber om ursäkt för kritiserad reklam67
- Högerbenet avlider vid körning.21
- Ljudproblem på ny dator från inet (nerkortad)69
- Skänkes Logitech Harmony + Telldus fjärrströmbrytare
- Säljes Beyerdynamic DT 700 Pro X
- Säljes i7-8700K, RTX 2080, 32GB 3200MHz DDR4, 1TB+500GB SSD, EKWB custom loop
- Skänkes Fractal Design Core 2500
- Säljes Speldator Både snabb och tyst. Med mycket lagring.
- Säljes Philips Hue White Ambiance GU10
- Säljes Be Quiet! TFX Power 3 Gold 300W
- Säljes BenQ GW2780 + G.Skill DDR5 6000 MHZ CL30 (2x16GB)
- Säljes i5 4670k, 16GB RAM, Sapphire Nitro RX580 4GB
- Säljes Philips 42" Evnia 42M2N8900 OLED 4K 138 Hz USB-C Ambiglow
Tester av chassi, grafikkort, processorer m.m.
- SweClockers Noob-byggarguide Del 210
- Bästa komponenterna enligt SweClockers medlemmar52
- SweClockers Noob-byggarguide Del 117
- Prispressat mejselkit är Testlabbets favorit40
- Corsair Platform 6: För dig som inte nöjer dig med Ikea-skrivbord11
- Airtec Pro Type1 – batteridrivet alternativ till tryckluft på burk128
- Snabbtest: Bli mer Pro med mindre tangentbord43
- Snabbtest: Högre spelprestanda med Intel APO46
- Snabbtest: Asus ROG Swift PG32UCDM – kryss i nästan alla rutor38
- Cooler Master Ncore 100 Max – lättbyggt minstingchassi17