create account

Advent of Code day 2 [spoilers] by markgritter

View this thread on: hive.blogpeakd.comecency.com
· @markgritter · (edited)
$1.08
Advent of Code day 2 [spoilers]
[Advent of Code Day 2](https://adventofcode.com/2018/day/2) asks us to do some string searches.  It took me about 40 minutes, and I can't say I'm particularly happy with the results, but it worked.

Part 1 asks us to find the number of words in the input with exactly two of some letter, or exactly three of some letter.

I decided this would be easiest if we sorted the letters in each word.  (In Python I'd probably just use a dictionary and count, tbh.)  I started out with a recursive solution trying to pattern match; my idea was:

[] -> false
xxyZ -> true
xxxZ -> recursively solve Z
xyZ -> recursively solve yZ

Unfortunately the case where there are three matching letters at the start is buggy, Z might start with another couple of the same letter.

Also, it's more idomatic in Haskell to use a higher-order function instead of writing the recursion yourself.  I came up with a way to use `foldl` to handle one letter at a time, and build up the frequency table in reverse order.  I don't think that lazy evaluation prevents us from processing the whole word before looking for frequency 2 or frequency 3, though.  If the output list were in-order, this would work but is accessing the last element of the list fast?  Or would reversing the list help?  I don't know.

```
countLetter :: [(Char,Int)] -> Char -> [(Char,Int)]
countLetter [] c = [(c,1)]
countLetter l@((c,n):rest) d
 | c == d = [(c,n+1)] ++ rest
 | otherwise = [(d,1)] ++ l

countLetters :: String -> [(Char,Int)]
countLetters s = foldl countLetter [] ( sort s )

exactly :: Int -> (Char,Int) -> Bool
exactly n (_,k) = (n == k)

exactlyTwoOfSomeLetter :: String -> Bool
exactlyTwoOfSomeLetter s = any (exactly 2) ( countLetters s ) 
  
exactlyThreeOfSomeLetter :: String -> Bool
exactlyThreeOfSomeLetter s = any (exactly 3) ( countLetters s ) 

checksum :: [String] -> Int
checksum l = (length (filter exactlyTwoOfSomeLetter l)) * (length (filter exactlyThreeOfSomeLetter l))
```

Part 2 asks us to find two words in the list that differ by just one letter (in a particular position.)  I think there are ways to solve this that aren't O(N^2) but I didn't believe any of them were going to be easy, or necessary.  

I wrote a recursive test for differing by one character:

```
differsByOne :: String -> String -> Bool
differsByOne [] [] = False
differsByOne (a:b) (c:d)
  | a/=c = (b==d)
  | otherwise = differsByOne b d
```

Maybe it would be better to zip the two words and then check the number of mismatches?  But this lets us use a whole-string compare on the tail which might be more efficient if the words were large.  They were 26 letters each, so I didn't need to worry about mismatched lengths.

The rest of the part 2 solution is just gross:

```
findMatch :: String -> [String] -> Maybe String
findMatch x l =
  case filter (differsByOne x) l of
    [] -> Nothing
    (a:b) -> Just a

distance1 :: [String] -> Maybe (String, String)
distance1 [] = Nothing
distance1 (x:s) =
  case findMatch x s of
    Nothing -> distance1 s
    Just y -> Just (x, y)
```

I looked for an equivalent to Python's `itertools.combinations( list, 2 )` which would be a better way to get all pairs.  Strangely, this does not seem to be part of the standard library.  There are various horrific-looking pieces of code here: https://stackoverflow.com/questions/21265454/subsequences-of-length-n-from-list-performance/21288092#21288092 and here: https://stackoverflow.com/questions/21775378/get-all-possible-combinations-of-k-elements-from-a-list when I was really expecting to see "just use X."

This Haskell package is closest to what I was expecting to find: http://hackage.haskell.org/package/permutation-0.5.0.5/docs/Data-Choose.html, but it works only on integers and so I'd still have to index into the original list.

[RosettaCode](https://rosettacode.org/wiki/Combinations#Haskell) gives this one-liner:

```
import Data.List (sort, subsequences)
comb m n = sort . filter ((==m) . length) $ subsequences [0..n-1]
```

which doesn't seem like a very efficient way to go about it, but it's hard for me to tell.  I'm kind of boggled that there isn't a standard way of doing this common combinatorial operation.

Full solution: https://github.com/mgritter/aoc2018/blob/master/day2/day2.hs

Things I learned today:
  * Not-equals is /= instead of !=
  * fold comes in at least 4 varieties and I understand the difference between "left" and "right" but not the primed and unprimed versions
  * No "all K-combinations" function?!?!
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 138 others
properties (23)
authormarkgritter
permlinkadvent-of-code-day-2-spoilers
categoryadventofcode
json_metadata{"tags":["adventofcode","programming","puzzle","haskell","functionalprogramming"],"links":["https://adventofcode.com/2018/day/2","https://stackoverflow.com/questions/21265454/subsequences-of-length-n-from-list-performance/21288092#21288092","https://stackoverflow.com/questions/21775378/get-all-possible-combinations-of-k-elements-from-a-list","http://hackage.haskell.org/package/permutation-0.5.0.5/docs/Data-Choose.html","https://rosettacode.org/wiki/Combinations#Haskell","https://github.com/mgritter/aoc2018/blob/master/day2/day2.hs"],"app":"steemit/0.1","format":"markdown"}
created2018-12-02 19:28:09
last_update2018-12-02 19:59:57
depth0
children3
last_payout2018-12-09 19:28:09
cashout_time1969-12-31 23:59:59
total_payout_value0.846 HBD
curator_payout_value0.238 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length4,493
author_reputation7,057,249,855,552
root_title"Advent of Code day 2 [spoilers]"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id76,257,226
net_rshares1,817,543,257,748
author_curate_reward""
vote details (202)
@paulag ·
Im impresses, because I love learning and I love to see people learn.  Keep it up, and keep sharing :-)
properties (22)
authorpaulag
permlinkre-markgritter-advent-of-code-day-2-spoilers-20181205t213631120z
categoryadventofcode
json_metadata{"tags":["adventofcode"],"app":"steemit/0.1"}
created2018-12-05 21:36:30
last_update2018-12-05 21:36:30
depth1
children0
last_payout2018-12-12 21:36:30
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length103
author_reputation274,264,287,951,003
root_title"Advent of Code day 2 [spoilers]"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id76,417,952
net_rshares0
@rantar ·
Wow that one looked trickier in Haskell, but good for you.
properties (22)
authorrantar
permlinkre-markgritter-advent-of-code-day-2-spoilers-20181204t031909388z
categoryadventofcode
json_metadata{"community":"busy","app":"busy/2.5.6","format":"markdown","tags":["adventofcode"],"users":[],"links":[],"image":[]}
created2018-12-04 03:19:09
last_update2018-12-04 03:19:09
depth1
children0
last_payout2018-12-11 03:19:09
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length58
author_reputation5,404,054,664,190
root_title"Advent of Code day 2 [spoilers]"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id76,325,161
net_rshares0
@steemstem ·
re-markgritter-advent-of-code-day-2-spoilers-20181206t104256943z
<div class='text-justify'> <div class='pull-left'> <br /> <center> <img width='125' src='https://i.postimg.cc/9FwhnG3w/steemstem_curie.png'> </center>  <br/> </div> <br /> <br /> 

 This post has been voted on by the **SteemSTEM** curation team and voting trail in collaboration with **@curie**. <br /> 
 If you appreciate the work we are doing then consider [voting](https://www.steemit.com/~witnesses) both projects for witness by selecting [**stem.witness**](https://steemconnect.com/sign/account_witness_vote?approve=1&witness=stem.witness) and [**curie**](https://steemconnect.com/sign/account_witness_vote?approve=1&witness=curie)! <br /> 
For additional information please join us on the [**SteemSTEM discord**]( https://discord.gg/BPARaqn) and to get to know the rest of the community! </div>
properties (22)
authorsteemstem
permlinkre-markgritter-advent-of-code-day-2-spoilers-20181206t104256943z
categoryadventofcode
json_metadata{"app":"bloguable-bot"}
created2018-12-06 10:43:00
last_update2018-12-06 10:43:00
depth1
children0
last_payout2018-12-13 10:43:00
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length800
author_reputation262,017,435,115,313
root_title"Advent of Code day 2 [spoilers]"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id76,443,323
net_rshares0