코드 #1의 출현(JavaScript 및 Haskell에서)

올해는 Advent of Code 에 참여하는 첫해이며 Haskell을 더 잘하고 JavaScript에서 유사한 문제 해결 방법을 찾을 수 있는 기회로 사용하겠다고 생각했습니다. 나는 실제로 답을 가장 빨리 찾을 수 있다고 생각되는 방법으로 각 퍼즐을 풀고 정답을 얻은 후 돌아가서 Haskell에서 더 나은 솔루션을 찾을 계획입니다. (오늘은 실제로 훌륭한 프로그래밍 인터페이스인 Excel을 사용했지만 나중에 더 자세히 설명하겠습니다.)

여기에서 문제를 요약할 것이지만 전체 내용을 확인하고 참여하려면 웹사이트를 확인해야 합니다!

1부



퍼즐 입력은 숫자 목록을 제공하고 전체 목록에 대해 두 개의 연속된 숫자가 증가하는 횟수를 찾도록 요청받습니다. 값 목록에서 단일 값을 계산하라는 요청을 받았을 때 처음 생각한 것은 접기/줄이기입니다. 불행하게도, 이 문제에 대한 접기의 각 단계는 이전 숫자와 함께 연속 증가의 누계를 추적해야 합니다. Haskell에서 이 작업을 수행하는 일반적인 트릭은 먼저 자체 꼬리로 목록을 압축하여 이렇게 연속된 숫자 쌍 목록으로 끝내는 것입니다. (이것을 작성하는 더 좋은 방법이 있지만 2부에서 왜 이렇게 작성했는지 알 수 있습니다.)

list = [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]
pairs :: [a] -> [(a, a)]
pairs (x:rest) = zip (x:rest) rest


그런 다음 연속 증가의 총합을 계산하기 위해 쌍 목록을 접을 수 있습니다.

answer = foldl (
  \ count (a, b) -> if b > a then count + 1 else count
) 0 (pairs list)


하스켈에서 이것을 하는 더 좋은 방법이 있을 것입니다. 개수와 이전 항목을 포함하는 누산기로 튜플을 사용하려고 했지만 제대로 작동하지 않는 것 같습니다. 그러나 이러한 접근 방식은 JavaScript에서 비교적 간단합니다.

[_, answer] = list.reduce(
  ([previous, count], current) => [
    current,
    current > previous ? count + 1 : count
  ], [Infinity, 0])


누산기에 대한 초기 값은 Infinity의 튜플이므로 첫 번째 항목과의 비교는 항상 더 작아지고 카운트 시작은 0입니다. 우리는 구조 분해를 사용하여 끝에 있는 튜플에서 답을 다시 가져옵니다.

두 번째 부분



이 부분은 세 개의 연속된 숫자의 연속적인 합을 비교한다는 점을 제외하면 첫 번째 부분과 유사합니다. 쌍 대신 목록에서 트리플이 필요한 것 같습니다. zip3 함수로 zip 개념을 확장할 수 있습니다.

triples :: [a] -> [(a, a, a)]
triples (x:y:rest) = zip3 (x:y:rest) (y:rest) rest


그런 다음 각 트리플의 합을 얻기 위해 매핑할 수 있습니다. 이 작업을 마치면 숫자 목록으로 돌아가서 다시 쌍을 이루어 연속 합계의 증가를 비교하고 이전과 같이 합계를 얻기 위해 접을 것입니다.

answer = foldl (
  \ count (a, b) -> if b > a then count + 1 else count
) 0 (pairs (map (\(x, y, z) -> x + y + z ) (triples list)))


엉망인 괄호를 수정하는 방법이 있지만 지금은 다루지 않겠습니다. 이전 항목을 추적하기 위해 튜플을 사용하는 초기 전략과 문제의 이 부분에 대한 전체 유형이 무너지므로 Haskell에서 수행한 작업을 복사합니다.

const zip = (a, b) => Array(Math.min(a.length, b.length))
  .fill().map((_,i) => [a[i], b[i]]);

const zip3 = (a, b, c) => Array(Math.min(a.length, b.length, c.length))
  .fill().map((_,i) => [a[i], b[i], c[i]]);

const pairs = ([x, ...rest]) => zip([x, ...rest], rest)

const triples = ([x, y, ...rest]) => zip3([x, y, ...rest], [y, ...rest], rest)

const answer = pairs(
  triples(list).map(([x, y, z]) => x + y + z)
).reduce((count, [a, b]) => b > a ? count + 1 : count, 0)


그것은 확실히 매우 우아한 해결책은 아니지만 마침내 거기에 도달했습니다. Excel에서 이 두 부분을 모두 해결하는 데 약 5분이 걸렸지만 이러한 Haskell 및 JavaScript 솔루션을 결합하는 데 약 2시간이 걸렸습니다.

Haskell에서 이 문제를 어떻게 해결하겠습니까? JavaScript에서는 어떻습니까? 함께 해킹한 것보다 더 나은 방법을 보고 싶습니다.

좋은 웹페이지 즐겨찾기