Un cartel que muestra las horas de apertura agrupadas de un café

20

Probablemente haya visto estas señales en las puertas de varias tiendas:

HORARIO DE APERTURA

lunes-viernes 0900-1800
sábado- domingo 1100-1530

La tarea aquí es generar un signo como ese, agrupando días consecutivos con el mismo horario de apertura, a partir de una lista de horarios de apertura para toda la semana. Tenga en cuenta que la semana se "ajusta" a lo que se considera consecutivo.

Entrada:

  • 7 elementos, que representan el horario de apertura de cada día de una semana, comenzando con el lunes.
  • Cada elemento es una cadena, en el formulario XXXX-XXXX
  • Entrada de ejemplo:

    0900-1800 0900-1800 0930-1730 0930-1730 0900-1500 1100-1500 1100-1500
    
  • Está bien enviar la entrada como una matriz (por ejemplo, como entrada a una función si no lee desde stdin)

Salida:

  • Una lista de horas de apertura, donde los días consecutivos con las mismas horas de apertura se muestran como un rango. Tenga en cuenta que el domingo (el último día) y el lunes (el primer día) también son días consecutivos.
  • Un día donde el día no tiene horarios de apertura similares a los días anteriores o posteriores se imprime solo
  • Los días se especifican en tres letras minúsculas: lun mar mié jue vie sáb dom
  • Recuerde que el primer elemento en la entrada corresponde a mon, al lado de tue, etc.
  • Los horarios de apertura se muestran como en la entrada
  • Dos ejemplos

    mon-fri 0900-1800, sat-sun 1100-1500
    mon-wed 1030-1530, thu 100-1800, fri-sun 1200-1630
    
  • La salida debe ordenarse, de modo que los rangos aparezcan en el orden en que lo hacen los días de la semana. Se prefiere que el lunes sea el primero, pero puede suceder que no sea el primero en un grupo porque la semana termina. En este caso, tue es el primer rango.

    tue-fri 0900-1800, sat-mon 1100-1500
    
  • No se agrupe a menos que sean consecutivos, aquí el miércoles y el viernes tienen el mismo horario de apertura, pero están separados por un jueves con diferentes horarios de apertura, por lo que se enumeran por sí mismos.

    mon-tue 1000-1200, wed 0900-1500, thu 1000-1800, fri 0900-1500, sat-sun 1000-1500
    
  • La salida puede estar separada por comas como los ejemplos aquí, o separada por una nueva línea como en el ejemplo de arriba.

Casos de prueba

La primera línea es entrada, la segunda línea es salida esperada

0900-1800 0900-1800 0900-1800 0900-1800 0900-1800 1100-1500 1100-1500
mon-fri 0900-1800, sat-sun 1100-1500

0900-1800 0900-1800 0900-1800 0930-1700 0900-1800 1100-1500 1100-1500
mon-wed 0900-1800, thu 0930-1700, fri 0900-1800, sat-sun 1100-1500

1100-1500 0900-1800 0900-1800 0900-1800 0900-1800 1100-1500 1100-1500
tue-fri 0900-1800, sat-mon 1100-1500

1100-1500 1100-1500 0900-1800 0900-1800 0900-1800 0900-1800 1100-1500
wed-sat 0900-1800, sun-tue 1100-1500

1200-1500 1100-1500 0900-1800 0900-1800 0900-1800 0900-1800 1100-1500
mon 1200-1500, tue 1100-1500, wed-sat 0900-1800, sun 1100-1500

Reglas

Este es el código de golf, por lo que gana la respuesta más corta en bytes.

Matsemann
fuente
77
Bienvenido a Programming Puzzles y Code Golf. Este es un buen desafío; ¡bien hecho! En el futuro, recomendaría usar el sandbox antes de publicar un desafío. (Ya sabes, por si acaso ...)
wizzwizz4
1
Tener domingo y lunes como consecutivos me parece extraño ...
Frédéric
1
Siento que debería haber un caso de prueba para "mon-sun" en caso de que alguna presentación no maneje adecuadamente ese caso base en particular.
Patrick Roberts el

Respuestas:

7

JavaScript (ES6), 182 173 170 163 157 bytes

Guardado 6 bytes con la ayuda de edc65

Toma datos como una matriz de cadenas e imprime directamente el resultado en la consola:

h=>{for(D="montuewedthufrisatsun".match(/.../g),d=c=i=j=0;j<8;y=d)h[i]==h[6]?i++:(v=h[d=(i+j++)%7])!=c&&(j>1&&console.log(D[x]+(x-y?'-'+D[y]:''),c),x=d,c=v)}

Formateado y comentado

h => {                               // input = list h of opening hours
  for(                               //
    D = "montuewedthufrisatsun"      // D = list of abbreviated names of days
        .match(/.../g),              //
    d =                              // d = current day of week
    c =                              // c = current opening hours
    i =                              // i = first day of week to process
    j = 0;                           // j = day counter
    j < 8;                           // stop when 7 days have been processed
    y = d                            // update y = last day of current day range
  )                                  //
  h[i] == h[6] ?                     // while the opening hours of day #i equal the opening
    i++                              // hours of sunday: increment i
  : (v = h[d = (i + j++) % 7]) != c  // else, if the new opening hours (v) of the current
    && (                             // day (d) doesn't match the current opening hours (c):
      j > 1 &&                       //   if this is not the first iteration:
        console.log(                 //     print:
          D[x] +                     //     - the first day of the current day range (x)
          (x - y ?                   //     - followed by either an empty string
            '-' + D[y]               //       or a '-' and the last day of the range
          : ''),                     //       (if they differ)
          c                          //     - the corresponding opening hours
        ),                           //   (endif)
      x = d,                         //   update x = first day of current day range
      c = v                          //   update c = current opening hours
    )                                // (endif)
}                                    // (end)

Casos de prueba

let f =

h=>{for(D="montuewedthufrisatsun".match(/.../g),d=c=i=j=0;j<8;y=d)h[i]==h[6]?i++:(v=h[d=(i+j++)%7])!=c&&(j>1&&console.log(D[x]+(x-y?'-'+D[y]:''),c),x=d,c=v)}

f(["0900-1800", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500", "1100-1500"]);
console.log('-');
f(["0900-1800", "0900-1800", "0900-1800", "0930-1700", "0900-1800", "1100-1500", "1100-1500"]);
console.log('-');
f(["1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500", "1100-1500"]);
console.log('-');
f(["1100-1500", "1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500"]);
console.log('-');
f(["1200-1500", "1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500"]);

Arnauld
fuente
D='montuewedthufrisatsun'.match(/.../g)el uso Dcomo una matriz en lugar de una función debería ahorrar algún byte
edc65
@ edc65: lamentablemente D()se puede llamar con -1(cuando buscamos 'el día antes del lunes'), que funciona substr()pero no funcionaría con una matriz.
Arnauld
@ edc65 - EDITAR: combinando su método con otra solución, esto definitivamente es una victoria. ¡Gracias!
Arnauld
3

Lote, 334 bytes

@echo off
set/af=l=w=0
set h=%7
call:l mon %1
call:l tue %2
call:l wed %3
call:l thu %4
call:l fri %5
call:l sat %6
call:l sun %7
if not %w%==0 set l=%w%
if %f%==0 set f=mon
call:l 0 0
exit/b
:l
if not %h%==%2 (
if %f%==0 (set w=%l%)else if %f%==%l% (echo %f% %h%)else echo %f%-%l% %h%
set f=%1
set h=%2
)
set l=%1

Toma la entrada como parámetros de línea de comando, emite cada grupo en una línea separada. Funciona comparando las horas de cada día con el día anterior, rastreando fcomo el primer día en el grupo, hcomo las horas para ese grupo, lcomo el último día en el grupo y wpara cuándo el último grupo regresa al comienzo de la semana. Cuando se encuentra una falta de coincidencia, el grupo anterior se imprime a menos que el ajuste semanal esté vigente. Finalmente, cuando se procesan todos los días, el último grupo se ajusta para cualquier ajuste semanal y si todas las horas resultaron iguales antes de salir. 0se usa como marcador de posición porque las cadenas vacías cuestan más bytes para comparar en Batch.

Neil
fuente
2

Gelatina , 87 84 80 75 bytes

  • 4bytes con la amable ayuda de @Dennis (solucionó un truco que usé con el 'rápido, "plano")

Estoy bastante seguro de que hay una mejor manera, pero por ahora:

Ṫ2ị$€;@µ+\µżṙ1’$Ṗị“ḅạṄMḤ9\E¥LḃɓṅÐĿ;$»s3¤Q€j€”-
ṙ7Ḷ¤Œr'€Ėµ2ịLµÐṂḢ
ÇṪḢ€ż@ÇÑ$G

TryiItOnline

¿Cómo?

            “ḅạṄMḤ9\E¥LḃɓṅÐĿ;$» - compressed string "montuewedthufrisatsun"
                  v  v
Ṫ2ị$€;@µ+\µżṙ1’$Ṗị -- s3¤Q€j€”- - Link 1, getDayStrings: [offset, groupedList]
Ṫ                               - Tail: get groupedList
 2ị$€                           - second index of each: get group sizes, e.g. mon-thu is 4
     ;@                         - concatenate (reversed arguments): prepend with offset
       µ                        - monadic chain separation
        +\                      - cumulative reduce with addition: start indexes
          µ                     - monadic chain separation
           ż                    - zip with
               $                - last two links as a monad
            ṙ1                  -     rotated left by one
              ’                 -     decrement:  end indexes
                Ṗ               - pop: remove last one, it's circular
                 ị              - index into
                        ¤       - last two links as a nilad
                    --          -     compressed string of weekdays (as shown at the top)
                      s3        -     split into 3s
                        Q€      - unique items for each: [tue,tue] -> [tue]
                          j€    - join each with
                            ”-  - literal string "-"

ṙ7Ḷ¤Œr'€Ėµ2ịLµÐṂḢ - Link 2: CalculateGroupingData: list of time strings
   ¤              - last two links as a nilad
ṙ                 -    rotate time strings list left by
 7Ḷ               -    range 7: [0,1,2,3,4,5,6]
       €          - for each
    Œr            -     run length encode
      '           -     flat - i.e. don't vectorise
        Ė         - enumerate [[1,[groupsFromMon]],[2,[groupsFromTue], ...]
         µ        - monadic chain separation
              ÐṂ  - filter for minimum of
             L    -     length of
          2ị      -     item at index 2: The number of groupings
                Ḣ - head: get the first occurring minimal (i.e Mon, or Tue, ...)

ÇṪḢ€ż@ÇÑ$G - Main link: list of time strings
Ç          - call last link (1) as a monad: get the offset and grouping
 Ṫ         - tail: get the grouping
  Ḣ€       - head each: get the time information
        $  - last two links as a monad
      Ç    -      call last link (1) as a monad: get the offset and grouping
       Ñ   -      call the next link as a monad: get the day strings
    ż@     - zip (with reversed arguments)
         G - arrange as a group (performs a tabulation to nicely align the result)
Jonathan Allan
fuente
1

JavaScript (ES6), 171 169 bytes

a=>a.map((e,d)=>(d='montuewedthufrisatsun'.substr(d*3,3),e!=h&&(f?o(f):w=l,f=d,h=e),l=d),f='',l=w='sun',h=a[6],o=f=>console.log((f==l?l:f+'-'+l)+' '+h))&&o(f||'mon',l=w)

Toma la entrada como una matriz y las salidas a la consola en líneas separadas. Esto es casi exactamente un puerto de mi respuesta Batch; fahora, por defecto, es una cadena vacía, mientras que también puedo usar el valor predeterminado ly wpara 'sun'(el uso de un valor centinela me ahorró 3 bytes en Batch porque pude fusionar la inicialización en set/a).

Neil
fuente
1

El tocino , 514 496 455 bytes

El programa BÁSICO a continuación se muestra con su sangría. Pero sin la sangría, consta de 455 bytes.

La idea es utilizar los horarios como índices de una matriz asociativa. Entonces, cada día representa un bit: lunes = bit 0, martes = bit 1, miércoles = bit 2 y así sucesivamente. Los valores reales para los miembros de la matriz asociativa se calculan por los bits respectivos de los días utilizando un OR binario.

Después de eso, se trata de verificar cuántos bits consecutivos están presentes en los miembros de la matriz asociativa, comenzando con el bit 0.

En caso de que el bit 0 y el bit 6 estén configurados, hay un ajuste de semana. En ese caso, comience a buscar el inicio de la siguiente secuencia de bits, memorizando esta posición de inicio. Imprima el resto de las secuencias, y tan pronto como se alcanza el bit 6, el rango del día debe finalizar con la posición memorizada antes.

LOCAL n$[]={"mon","tue","wed","thu","fri","sat","sun"}
GLOBAL p ASSOC int
SUB s(VAR t$ SIZE a)
    FOR i = 0 TO a-1
        p(t$[i])=p(t$[i])|BIT(i)
    NEXT
    LOOKUP p TO c$ SIZE o
    b=e=0
    REPEAT
        FOR i=0 TO o-1
            IF p(c$[i])&BIT(b) THEN
                IF b=0 AND p(c$[i])&65=65 THEN
                    WHILE p(c$[i])&BIT(b)
                        INCR b
                    WEND
                    e=b
                    BREAK
                FI
                ?n$[b];
                r=b
                REPEAT
                    INCR b
                UNTIL NOT(p(c$[i])&BIT(b))
                IF e AND b>6 THEN
                    ?"-",n$[e-1];
                ELIF b-r>1 THEN
                    ?"-",n$[b-1];
                FI
                ?" ",c$[i]
            FI
        NEXT
    UNTIL b>6
    FREE p
ENDSUB

Usando las siguientes llamadas para invocar el SUB:

s("0900-1800", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500", "1100-1500")
PRINT "======"
s("0900-1800", "0900-1800", "0900-1800", "0930-1700", "0900-1800", "1100-1500", "1100-1500")
PRINT "======"
s("1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500", "1100-1500")
PRINT "======"
s("1100-1500", "1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500")
PRINT "======"
s("1200-1500", "1100-1500", "0900-1800", "0900-1800", "0900-1800", "0900-1800", "1100-1500")

Salida :

mon-fri 0900-1800
sat-sun 1100-1500
======
mon-wed 0900-1800
thu 0930-1700
fri 0900-1800
sat-sun 1100-1500
======
tue-fri 0900-1800
sat-mon 1100-1500
======
wed-sat 0900-1800
sun-tue 1100-1500
======
mon 1200-1500
tue 1100-1500
wed-sat 0900-1800
sun 1100-1500
Peter
fuente