Forum Programmation.autre Avent du Code, jour 6

PostĂ© par (site web personnel) . Licence CC By‐SA.
Étiquettes :
5
6
déc.
2022

Avent du Code, jour 6.

On va pouvoir partir en expĂ©dition dans la jungle. Enfin, demain. Peut-ĂȘtre. Pour le moment, comme nous avons beaucoup d'expĂ©rience avec ces machins, les lutins nous ont refilĂ© un transmetteur pĂ©tĂ©, il faut le rĂ©parer.

  • # En Python

    PostĂ© par (site web personnel) . ÉvaluĂ© Ă  4.

    from typing import Iterable
    def solve1(lines: Iterable[str]) -> int:
     """Solve part 1 of today's puzzle"""
     for line in lines:
     # There is actually only one line :-)
     for i in range(4, len(line) - 1): # ignore final '\n'
     if len(set(line[i-4:i])) >= 4:
     return i
     return 0
    def solve2(lines: Iterable[str]) -> int:
     """Solve part 2 of today's puzzle"""
     for line in lines:
     # There is actually only one line :-)
     for i in range(14, len(line) - 1): # ignore final '\n'
     if len(set(line[i-14:i])) >= 14:
     return i
     return 0

    Le fait que mes fonctions mangent un itérable de chaßnes vient des fonctions utilitaires que j'ai codées pour intégrer ça facilement. Ici, ça donne quelque chose d'un peu artificiel puisqu'il n'y a qu'une ligne à lire.

    Je ne suis pas du tout satisfait par le fait de transformer Ă  chaque fois un bout glissant de la chaĂźne d'entrĂ©e en un ensemble. J'aimerais bien faire quelque chose d'un peu mieux optimisĂ©, mais je n'ai rien de probant en tĂȘte.

    • [^] # Re: En Python

      PostĂ© par . ÉvaluĂ© Ă  2.

      J'ai simplement fait un ring buffer :

      from collections import deque
      d = deque([], maxlen=14)
      with open("input", "r") as h:
       for l in h:
       l = l.strip()
       for i, c in enumerate(l):
       d.append(c)
       if len(set(d)) == 14:
       print(i + 1)
      • [^] # Re: En Python

        PostĂ© par (site web personnel) . ÉvaluĂ© Ă  3.

        Ça n'optimise rien du tout, si ?

        Je veux dire, nous avons tous deux la ligne entiĂšre en mĂ©moire, mais lĂ  oĂč j'en prends Ă  chaque fois une tranche pour la convertir en ensemble et regarder sa longueur, tu enfonces un par un chacun de ses caractĂšres dans une file Ă  taille limitĂ©e, que tu convertis en ensemble pour regarder sa longueur.

        Quoique, ça évite une copie de chaßne à chaque étape, c'est ça ? La file à taille limitée étant persistante et ne copiant qu'un caractÚre à chaque fois.

        • [^] # Re: En Python

          PostĂ© par (Mastodon) . ÉvaluĂ© Ă  3.

          Franchement, je ne fais pas mieux.
          Toute optimisation semble compliquer terriblement le code.
          Et vu la taille des données...

          C'est quoi la citation Ă  propos des optimisations trop tĂŽt dans le code ? :)

          • Yth.
    • [^] # Re: En Python

      PostĂ© par . ÉvaluĂ© Ă  2.

      Pas mieux

      import sys
      s = sys.stdin.read()
      for i in range(14, len(s)):
       if len(set(s[i-14:i])) == 14:
       print(i)
       break
    • [^] # Re: En Python

      PostĂ© par . ÉvaluĂ© Ă  4.

      Je ne suis pas du tout satisfait par le fait de transformer à chaque fois un bout glissant de la chaßne d'entrée en un ensemble

      Ma premiĂšre solution Ă©tait Ă  base de deque et n'utilisait pas set. L'idĂ©e Ă©tant que si tu as dĂ©doublonnĂ© la fenĂȘtre prĂ©cĂ©dente, et tu as un nouveau caractĂšre, seul celui-ci peu crĂ©er un doublon. Donc au lieu de tout dĂ©doublonner (set), tu dĂ©doublonnes que par rapport Ă  ce nouveau caractĂšre.

      Voici:

      import sys
      from collections import deque
      dq = deque()
      for (i,c) in enumerate(sys.stdin.read()):
       equals = list(filter(lambda x: c == x[1], enumerate(dq))) # find duplicate
       assert len(equals)<2
       if len(equals)==1: # remove left part until a char equal to c, included
       for _ in range(equals[0][0]+1):
       dq.popleft()
       if len(dq) == 13: # if we have 13+1 distinct chars, we're good
       print(i+1)
       break
       dq.append(c)

      Mais honnĂȘtement, c'est bien plus compliquĂ© pour pas grand chose.

      Faudrait faire du profilage cpu et ram pour comparer mais sur la taille de mon input et avec la commande time, rien de visible. Et je crains que construire un set de 14 caractÚres ne soit pas plus coûteux que de manipuler la deque et et le filter.

  • # un bout de AWK

    PostĂ© par . ÉvaluĂ© Ă  4. DerniĂšre modification le 06 dĂ©cembre 2022 Ă  20:14.

    Finalement une solution en AWK, pas si moche quand on a pas de "set".

    BEGIN { W = 14 }
    {
     for (i=1; i<=length($1); i++) {
     window = substr($1,i,W)
     # compare each char of window to all char of window
     S = 0 # to count match
     for (j=1; j<=W; j++) {
     for (k=1; k<=W; k++) {
     S+= (substr(window,j,1) == substr(window,k,1)) ? 1 : 0
     }
     }
     if (S == W) { # if each char match only itsef
     print i + W - 1
     next # finish
     }
     }
    }
  • # en Go

    PostĂ© par . ÉvaluĂ© Ă  2.

    Je suis à la bourre, j'ai pris du retard sur le n°5. J'ai trouvé celui ci plus facile, solution en Go (fonction principale) :

    func startOfPacket(line string, msgLen int) int {
     l := len(line)
     if l <= msgLen {
     return -1
     }
    mainloop:
     for i := msgLen - 1; i < l; i++ {
     message := line[i-msgLen+1 : i+1]
     chars := make(map[rune]int, msgLen)
     for _, r := range message {
     chars[r]++
     if chars[r] == 2 {
     continue mainloop
     }
     }
     return i + 1
     }
     return -1
    }

Suivre le flux des commentaires

Note : les commentaires appartiennent Ă  celles et ceux qui les ont postĂ©s. Nous n’en sommes pas responsables.