Find the length of a frequency-change cycle (Advent of Code 2018)











up vote
3
down vote

favorite












I tried to do the second part of the 1. December challenge of Advent of Code in Haskell. I'm fairly new to Haskell but I have plenty of experience in other (procedural) languages. I struggled with the challenge for hours because the program would hang and it wouldn't produce any output although I couldn't find a problem in my code. Eventually it turned out that my programm worked correctly but it just took very long. To be exact the program took 2 minutes and 40 seconds. According to Advent of Code every challenge should able to execute within 15 seconds though.



So what makes my code so slow?



The task:




You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice.



For example, using the same list of changes above, the device would
loop as follows:



Current frequency  0, change of +1; resulting frequency  1.
Current frequency 1, change of -2; resulting frequency -1.
Current frequency -1, change of +3; resulting frequency 2.
Current frequency 2, change of +1; resulting frequency 3.
(At this point, the device continues from the start of the list.)
Current frequency 3, change of +1; resulting frequency 4.
Current frequency 4, change of -2; resulting frequency 2, which has already been seen.


In this example, the first frequency reached twice is 2. Note that
your device might need to repeat its list of frequency changes many
times before a duplicate frequency is found, and that duplicates might
be found while in the middle of processing the list.



Here are other examples:



+1, -1 first reaches 0 twice.
+3, +3, +4, -2, -4 first reaches 10 twice.
-6, +3, +8, +5, -6 first reaches 5 twice.
+7, +7, -2, -7, -4 first reaches 14 twice.


What is the first frequency your device reaches twice?




My code:



module DayOnePartTwo where

import System.IO
import Data.Maybe

inputFileName = "input.txt"

input :: String -> [Integer]
input contents = toNum (cleanNumbers (splitNumbers contents))
where
cleanNumbers strs = map removeLeadingPlus strs
splitNumbers string = words string
toNum numbers = map read numbers
removeLeadingPlus str = if str !! 0 == '+' then tail str else str

accumulate :: [Integer] -> [Integer]
accumulate list = accumulator list 0
where
accumulator :: Num a => [a] -> a -> [a]
accumulator (x:xs) state = (x + state) : accumulator xs (x + state)
accumulator state =

duplicate :: [Integer] -> Maybe Integer
duplicate list = dup list [0]
where
dup (x:xs) visited =
if elem x visited
then Just x
else dup xs (x:visited)
dup _ = Nothing

firstCyclicDuplicate :: [Integer] -> Maybe Integer
firstCyclicDuplicate list = duplicate (accumulate cycledList)
where
cycledList = cycle list

main :: IO ()
main = do
contents <- readFile inputFileName
case (firstCyclicDuplicate (input contents)) of
Just a -> print (show a)
Nothing -> print "There is no first duplicate"


This seems to be related to slow advent of code 2018 day 1 part 2 solution in haskell although my algorithm is different.










share|improve this question









New contributor




Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
























    up vote
    3
    down vote

    favorite












    I tried to do the second part of the 1. December challenge of Advent of Code in Haskell. I'm fairly new to Haskell but I have plenty of experience in other (procedural) languages. I struggled with the challenge for hours because the program would hang and it wouldn't produce any output although I couldn't find a problem in my code. Eventually it turned out that my programm worked correctly but it just took very long. To be exact the program took 2 minutes and 40 seconds. According to Advent of Code every challenge should able to execute within 15 seconds though.



    So what makes my code so slow?



    The task:




    You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice.



    For example, using the same list of changes above, the device would
    loop as follows:



    Current frequency  0, change of +1; resulting frequency  1.
    Current frequency 1, change of -2; resulting frequency -1.
    Current frequency -1, change of +3; resulting frequency 2.
    Current frequency 2, change of +1; resulting frequency 3.
    (At this point, the device continues from the start of the list.)
    Current frequency 3, change of +1; resulting frequency 4.
    Current frequency 4, change of -2; resulting frequency 2, which has already been seen.


    In this example, the first frequency reached twice is 2. Note that
    your device might need to repeat its list of frequency changes many
    times before a duplicate frequency is found, and that duplicates might
    be found while in the middle of processing the list.



    Here are other examples:



    +1, -1 first reaches 0 twice.
    +3, +3, +4, -2, -4 first reaches 10 twice.
    -6, +3, +8, +5, -6 first reaches 5 twice.
    +7, +7, -2, -7, -4 first reaches 14 twice.


    What is the first frequency your device reaches twice?




    My code:



    module DayOnePartTwo where

    import System.IO
    import Data.Maybe

    inputFileName = "input.txt"

    input :: String -> [Integer]
    input contents = toNum (cleanNumbers (splitNumbers contents))
    where
    cleanNumbers strs = map removeLeadingPlus strs
    splitNumbers string = words string
    toNum numbers = map read numbers
    removeLeadingPlus str = if str !! 0 == '+' then tail str else str

    accumulate :: [Integer] -> [Integer]
    accumulate list = accumulator list 0
    where
    accumulator :: Num a => [a] -> a -> [a]
    accumulator (x:xs) state = (x + state) : accumulator xs (x + state)
    accumulator state =

    duplicate :: [Integer] -> Maybe Integer
    duplicate list = dup list [0]
    where
    dup (x:xs) visited =
    if elem x visited
    then Just x
    else dup xs (x:visited)
    dup _ = Nothing

    firstCyclicDuplicate :: [Integer] -> Maybe Integer
    firstCyclicDuplicate list = duplicate (accumulate cycledList)
    where
    cycledList = cycle list

    main :: IO ()
    main = do
    contents <- readFile inputFileName
    case (firstCyclicDuplicate (input contents)) of
    Just a -> print (show a)
    Nothing -> print "There is no first duplicate"


    This seems to be related to slow advent of code 2018 day 1 part 2 solution in haskell although my algorithm is different.










    share|improve this question









    New contributor




    Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      I tried to do the second part of the 1. December challenge of Advent of Code in Haskell. I'm fairly new to Haskell but I have plenty of experience in other (procedural) languages. I struggled with the challenge for hours because the program would hang and it wouldn't produce any output although I couldn't find a problem in my code. Eventually it turned out that my programm worked correctly but it just took very long. To be exact the program took 2 minutes and 40 seconds. According to Advent of Code every challenge should able to execute within 15 seconds though.



      So what makes my code so slow?



      The task:




      You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice.



      For example, using the same list of changes above, the device would
      loop as follows:



      Current frequency  0, change of +1; resulting frequency  1.
      Current frequency 1, change of -2; resulting frequency -1.
      Current frequency -1, change of +3; resulting frequency 2.
      Current frequency 2, change of +1; resulting frequency 3.
      (At this point, the device continues from the start of the list.)
      Current frequency 3, change of +1; resulting frequency 4.
      Current frequency 4, change of -2; resulting frequency 2, which has already been seen.


      In this example, the first frequency reached twice is 2. Note that
      your device might need to repeat its list of frequency changes many
      times before a duplicate frequency is found, and that duplicates might
      be found while in the middle of processing the list.



      Here are other examples:



      +1, -1 first reaches 0 twice.
      +3, +3, +4, -2, -4 first reaches 10 twice.
      -6, +3, +8, +5, -6 first reaches 5 twice.
      +7, +7, -2, -7, -4 first reaches 14 twice.


      What is the first frequency your device reaches twice?




      My code:



      module DayOnePartTwo where

      import System.IO
      import Data.Maybe

      inputFileName = "input.txt"

      input :: String -> [Integer]
      input contents = toNum (cleanNumbers (splitNumbers contents))
      where
      cleanNumbers strs = map removeLeadingPlus strs
      splitNumbers string = words string
      toNum numbers = map read numbers
      removeLeadingPlus str = if str !! 0 == '+' then tail str else str

      accumulate :: [Integer] -> [Integer]
      accumulate list = accumulator list 0
      where
      accumulator :: Num a => [a] -> a -> [a]
      accumulator (x:xs) state = (x + state) : accumulator xs (x + state)
      accumulator state =

      duplicate :: [Integer] -> Maybe Integer
      duplicate list = dup list [0]
      where
      dup (x:xs) visited =
      if elem x visited
      then Just x
      else dup xs (x:visited)
      dup _ = Nothing

      firstCyclicDuplicate :: [Integer] -> Maybe Integer
      firstCyclicDuplicate list = duplicate (accumulate cycledList)
      where
      cycledList = cycle list

      main :: IO ()
      main = do
      contents <- readFile inputFileName
      case (firstCyclicDuplicate (input contents)) of
      Just a -> print (show a)
      Nothing -> print "There is no first duplicate"


      This seems to be related to slow advent of code 2018 day 1 part 2 solution in haskell although my algorithm is different.










      share|improve this question









      New contributor




      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I tried to do the second part of the 1. December challenge of Advent of Code in Haskell. I'm fairly new to Haskell but I have plenty of experience in other (procedural) languages. I struggled with the challenge for hours because the program would hang and it wouldn't produce any output although I couldn't find a problem in my code. Eventually it turned out that my programm worked correctly but it just took very long. To be exact the program took 2 minutes and 40 seconds. According to Advent of Code every challenge should able to execute within 15 seconds though.



      So what makes my code so slow?



      The task:




      You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice.



      For example, using the same list of changes above, the device would
      loop as follows:



      Current frequency  0, change of +1; resulting frequency  1.
      Current frequency 1, change of -2; resulting frequency -1.
      Current frequency -1, change of +3; resulting frequency 2.
      Current frequency 2, change of +1; resulting frequency 3.
      (At this point, the device continues from the start of the list.)
      Current frequency 3, change of +1; resulting frequency 4.
      Current frequency 4, change of -2; resulting frequency 2, which has already been seen.


      In this example, the first frequency reached twice is 2. Note that
      your device might need to repeat its list of frequency changes many
      times before a duplicate frequency is found, and that duplicates might
      be found while in the middle of processing the list.



      Here are other examples:



      +1, -1 first reaches 0 twice.
      +3, +3, +4, -2, -4 first reaches 10 twice.
      -6, +3, +8, +5, -6 first reaches 5 twice.
      +7, +7, -2, -7, -4 first reaches 14 twice.


      What is the first frequency your device reaches twice?




      My code:



      module DayOnePartTwo where

      import System.IO
      import Data.Maybe

      inputFileName = "input.txt"

      input :: String -> [Integer]
      input contents = toNum (cleanNumbers (splitNumbers contents))
      where
      cleanNumbers strs = map removeLeadingPlus strs
      splitNumbers string = words string
      toNum numbers = map read numbers
      removeLeadingPlus str = if str !! 0 == '+' then tail str else str

      accumulate :: [Integer] -> [Integer]
      accumulate list = accumulator list 0
      where
      accumulator :: Num a => [a] -> a -> [a]
      accumulator (x:xs) state = (x + state) : accumulator xs (x + state)
      accumulator state =

      duplicate :: [Integer] -> Maybe Integer
      duplicate list = dup list [0]
      where
      dup (x:xs) visited =
      if elem x visited
      then Just x
      else dup xs (x:visited)
      dup _ = Nothing

      firstCyclicDuplicate :: [Integer] -> Maybe Integer
      firstCyclicDuplicate list = duplicate (accumulate cycledList)
      where
      cycledList = cycle list

      main :: IO ()
      main = do
      contents <- readFile inputFileName
      case (firstCyclicDuplicate (input contents)) of
      Just a -> print (show a)
      Nothing -> print "There is no first duplicate"


      This seems to be related to slow advent of code 2018 day 1 part 2 solution in haskell although my algorithm is different.







      beginner programming-challenge haskell time-limit-exceeded






      share|improve this question









      New contributor




      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 16 mins ago









      200_success

      127k15148412




      127k15148412






      New contributor




      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 5 hours ago









      Aaronmacaron

      161




      161




      New contributor




      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Aaronmacaron is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Aaronmacaron is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208844%2ffind-the-length-of-a-frequency-change-cycle-advent-of-code-2018%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          Aaronmacaron is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Aaronmacaron is a new contributor. Be nice, and check out our Code of Conduct.













          Aaronmacaron is a new contributor. Be nice, and check out our Code of Conduct.












          Aaronmacaron is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208844%2ffind-the-length-of-a-frequency-change-cycle-advent-of-code-2018%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          Refactoring coordinates for Minecraft Pi buildings written in Python