• # un bout de AWK

    Posté par  . Évalué à 4.

    Problème assez trivial aujourd'hui

    partie 1

    # run with: awk -F ',|-' -f part1.awk input
    ($3>=$1 && $4<=$2) || ($1>=$3 && $2<=$4) {n++}
    END {print n}

    partie 2

    # run with: awk -F ',|-' -f part2.awk input
    $3>$2 || $1>$4 {n++}
    END {print NR-n}
    • [^] # Re: un bout de AWK

      Posté par  (site web personnel) . Évalué à 5.

      C'était en effet parfaitement taillé pour Awk !

      • [^] # Re: un bout de AWK

        Posté par  . Évalué à 4.

        Oui, quand la plus grosse partie est de lire l'input ligne à ligne, de la tailler en colonne, de mettre ça dans des variables puis de faire un petit calcul, c'est du pain béni pour AWK :)

        C'est quand il faut construire et manipuler des structures de données complexe que Python prend sa revanche.

        • [^] # Re: un bout de AWK

          Posté par  (site web personnel) . Évalué à 3.

          C'est tout à fait ça. Mais à vrai dire, dès que le problème que je cherche à résoudre n'est pas un truc jetable, en particulier lorsqu'il s'agira de le montrer à d'autres ou de revenir dessus, j'utilise de moins en moins Awk.

          Je trouve en effet que, sauf quand c'est vraiment très simple, ça donne quelque chose de très peu compréhensible à la lecture ou à la relecture.

          • [^] # Re: un bout de AWK

            Posté par  . Évalué à 3.

            Oui je dirai que ce n'est pas un langage qui passe à l'échelle, en nombre de lignes et en nombre de contributeurs.

            C'est un langage de niche : manipuler de la donnée tabulaire avec concision et une bonne perf. En AWK t'es facilement à 1M/s

            Moi ça m'a sauvé les miches lors d'une mise en production de nuit, d'un système assez critique et assez coûteux aussi. On devait insérer 20M d'enregistrements dans la base. Sauf que les données de départ (xml) étaient loin d'être propre. Si on arrive pas à initialiser la DB, on repousse la MEP.

            J'ai du retailler et retravailler des lots d'enregistrements pour faire du rampup (lots de plus en plus gros tant que ça passe) et de la reprise sur erreur. Je peux dire qu'à ce moment là, au milieu de la nuit, t'es content de pouvoir exprimer facilement un petit traitement itérer rapidement et produire le résultat super vite.

  • # En Python

    Posté par  (site web personnel) . Évalué à 4.

    En Python, en utilisant une classe dédiée (je trouve que ça se lit mieux ainsi) :

    from typing import Iterable, Tuple
    
    import aoc
    
    
    class Interval:
        """An interval of integers"""
        def __init__(self, start: int, end: int):
            """Create a new interval of integers, from start to end included"""
            self.start = start
            self.end = end
    
        def includes(self, other):
            """Does this interval include the other one?"""
            return self.start <= other.start and self.end >= other.end
    
        def overlaps(self, other):
            """Does this interval overlap the other one?"""
            return self.end >= other.start and self.start <= other.end
    
    
    def import_interval(s: str) -> Interval:
        """Import an interval from a string such as "2-4" """
        part1, part2 = s.split('-')
        return Interval(int(part1), int(part2))
    
    
    def import_pairs(lines: Iterable[str]) -> Iterable[Tuple[Interval, Interval]]:
        """Import a pair of intervals from a line such as "2-4,5-8\\n" """
        for line in lines:
            part1, part2 = line.rstrip().split(',')
            yield import_interval(part1), import_interval(part2)
    
    
    def solve_both(lines: Iterable[str]) -> Tuple[int, int]:
        """Solve both parts of today's puzzle"""
        inclusions = 0
        overlaps = 0
        for a1, a2 in import_pairs(lines):
            if a1.includes(a2) or a2.includes(a1):
                inclusions += 1
            if a1.overlaps(a2):
                overlaps += 1
        return inclusions, overlaps
  • # un peu de sh

    Posté par  (site web personnel, Mastodon) . Évalué à 1. Dernière modification le 12 décembre 2022 à 01:39.

    Pour la première partie.

    #!/bin/sh
    # $1: input file
    
    for c in 'grep' 'seq' 'test'
    do
        if ! command -v "$c" >/dev/null
        then
            echo "Error: command '$c' not found" >&2
            exit 3
        fi
    done
    
    if test -z "$1"
    then
        echo "Please call me with an input file..." >&2
        exit 1
    fi
    
    if grep -Eqsv '^[0-9]+-[0-9]+,[0-9]+-[0-9]+$' "$1"
    then
        echo "Found invalid line, check the file!" >&2
        exit 2
    fi
    _if="$1"
    
    # First or Second elves in paire
    # Start or End of section number
    _oc=0 # Overlap Counter
    while IFS='-,' read -r _fs _fe _ss _se <&3
    do
        _s1=",$( seq -s ',' $_fs $_fe )" # 1st range sections list
        _s2=",$( seq -s ',' $_ss $_se )" # 2nd range sections list
        if test -z "${_s1##*$_s2*}" ||
            test -z "${_s2##*$_s1*}"
        then
            _oc=$(( _ic + 1 ))
        fi
    done 3<"$_if"
    echo "$_oc"

    Je ne sais pas pourquoi ça m'a fait penser à seq et jot (que j'ai déjà eu à mentionner.)

        _s1=",$( jot -s ',' - $_fs $_fe )," # 1st range sections list
        _s2=",$( jot -s ',' - $_ss $_se )," # 2nd range sections list

    L'écriture en extension a été inspiré par l'exemple donné

    .234.....  2-4
    .....678.  6-8

    …mais j'utilise un séparateur car on peut avoir des nombre de plusieurs chiffres

    ,2,3,4, 2-4
    ,6,7,8, 6-8

    Après il suffit de vérifier qu'une des deux sous-chaines est dans l'autre. :)
    Ici j'ai utilisé les possibilités de substitution et expansion du shell, mais on peut faire appel à une autre commande pour plus de lisibilité.

        if echo "$_s2" | grep -qs "$_s1"
        then
            _oc=$(( _ic + 1 ))
        elif echo "$_s1" | grep -qs "$_s2"
        then
            _oc=$(( _ic + 1 ))
        fi

    Noter que l'on peut utiliser seq et jot sans option -s puis rediriger dans un fichier distinct puis appliquer comm aux deux fichiers comme déjà vu.
    Exceptionnellement, je mentionne deux commandes non POSIX mais répandues (cependant la syntaxe du script demeure sans bashism.) On peut remplacer par une fonction maison pour plus de portabilité.
    Dans tous les cas, on traite le problème en peu de lignes avec les outils disponibles. :)

    “It is seldom that liberty of any kind is lost all at once.” ― David Hume

    • [^] # Re: un peu de sh

      Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 12 décembre 2022 à 02:02.

      Pour la seconde partie ce fut un peu plus tricky car il faut trouver un moyen de comparer deux listes ou tableaux (première idée qui m'est venue.) J'ai initialement pensé à faire appel à dc mais c'est plutôt cryptique en plus d'être lent.
      Finalement, on peut partir sur la dernière piste précédemment évoquée.

      #!/bin/sh
      # $1: input file
      
      for c in 'comm' 'grep' 'seq' 'test'
      do
          if ! command -v "$c" >/dev/null
          then
              echo "Error: command '$c' not found" >&2
              exit 3
          fi
      done
      
      if test -z "$1"
      then
          echo "Please call me with an input file..." >&2
          exit 1
      fi
      
      if grep -Eqsv '^[0-9]+-[0-9]+,[0-9]+-[0-9]+$' "$1"
      then
          echo "Found invalid line, check the file!" >&2
          exit 2
      fi
      _if="$1"
      
      # First or Second elves in paire
      # Start or End of section number
      _s1=$( mktemp ) # 1st range sections list
      _s2=$( mktemp ) # 2nd range sections list
      _oc=0 # Overlap Counter
      while IFS='-,' read -r _fs _fe _ss _se <&3
      do
          seq $_fs $_fe >"$_s1"
          seq $_ss $_se >"$_s2"
          if test -n "$( comm -12 "$_s1" "$_s2" )"
          then
              _oc=$(( _oc + 1 ))
          fi
      done 3<"$_if"
      rm "$_s1" "$_s2"
      echo "$_oc"

      Il est à noter que, comme pour pierre-feuille-ciseau, il est possible d'utiliser l'évaluation arithmétique du shell.

      _oc=0 # all Overlap Counter
      while IFS='-,' read -r _fs _fe _ss _se <&3
      do
          _oc=$(( _oc + !( (_ss>_fe) || (_fs>_se) ) ))
      done 3<"$_if"
      echo "$_oc"

      Maintenant paye ton moins.

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

Suivre le flux des commentaires

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