Um sinal mostrando o horário de funcionamento agrupado de um café


20

Você provavelmente já viu estas placas nas portas de várias lojas:

HORÁRIO DE ABERTURA

segunda-feira 0900-1800
sáb-dom 1100-1530

A tarefa aqui é gerar um sinal como esse, agrupando dias consecutivos com o mesmo horário de funcionamento, a partir de uma lista de horários de funcionamento para toda a semana. Observe que a semana "termina" pelo que é considerado consecutivo.

Entrada:

  • 7 elementos, representando o horário de funcionamento de cada dia em uma semana, começando na segunda-feira.
  • Cada elemento é uma sequência, no formato XXXX-XXXX
  • Exemplo de entrada:

    0900-1800 0900-1800 0930-1730 0930-1730 0900-1500 1100-1500 1100-1500
    
  • Não há problema em enviar a entrada como uma matriz (por exemplo, como entrada para uma função se você não ler a partir de stdin)

Saída:

  • Uma lista de horários de funcionamento, em que dias consecutivos com o mesmo horário de funcionamento são mostrados como um intervalo. Observe que domingo (o último dia) e segunda-feira (o primeiro dia) também são dias consecutivos.
  • Um dia em que o dia não tem horário de funcionamento semelhante aos dias anteriores ou posteriores é impresso por si só
  • Os dias são especificados como três letras minúsculas: segunda a quarta a sexta
  • Lembre-se de que o primeiro elemento na entrada corresponde a seg, próximo a ter etc.
  • O horário de funcionamento é mostrado como na entrada
  • Dois exemplos

    mon-fri 0900-1800, sat-sun 1100-1500
    mon-wed 1030-1530, thu 100-1800, fri-sun 1200-1630
    
  • A saída deve ser classificada, para que os intervalos apareçam na ordem dos dias da semana. É preferível segunda-feira para ser o primeiro, mas pode acontecer que não seja o primeiro de um grupo porque a semana termina. Portanto, neste caso, ter é o primeiro intervalo.

    tue-fri 0900-1800, sat-mon 1100-1500
    
  • Não agrupe a menos que seja consecutivo. Aqui, quarta e sexta-feira têm o mesmo horário de funcionamento, mas são separadas por uma quinta-feira com horários diferentes, para que sejam listados sozinhos.

    mon-tue 1000-1200, wed 0900-1500, thu 1000-1800, fri 0900-1500, sat-sun 1000-1500
    
  • A saída pode ser separada por vírgula como os exemplos aqui, ou separada por uma nova linha, como no exemplo na parte superior.

Casos de teste

Primeira linha é entrada, segunda linha é saída 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

Regras

Isso é código-golfe, então a resposta mais curta em bytes vence.


7
Bem-vindo à programação de quebra-cabeças e código de golfe. Este é um bom desafio; bem feito! No futuro, eu recomendaria usar a sandbox antes de postar um desafio. (Você sabe, apenas no caso ...)
wizzwizz4

1
Ter o domingo e a segunda-feira consecutivos me parece estranho ...
Frédéric

1
Sinto que deveria haver um caso de teste para "seg-dom", caso algum envio não lide adequadamente com esse caso-base em particular.
Patrick Roberts

Respostas:


7

JavaScript (ES6), 182 173 170 163 157 bytes

Economizou 6 bytes com a ajuda de edc65

Recebe a entrada como uma matriz de seqüências de caracteres e imprime diretamente o resultado no console:

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)}

Formatado e 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 teste

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"]);


D='montuewedthufrisatsun'.match(/.../g)utilizando Dcomo uma matriz em vez de uma função deve poupar algum byte
edc65

@ edc65 - Infelizmente D()pode ser chamado com -1(quando procuramos 'o dia antes de segunda-feira'), que funciona com, substr()mas não funcionaria, com uma matriz.
Arnauld #

@ edc65 - EDIT: combinando seu método com outra correção, essa é definitivamente uma vitória. Obrigado!
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

Recebe a entrada como parâmetros da linha de comando e gera cada grupo em uma linha separada. Funciona comparando as horas de cada dia com o dia anterior, rastreando fcomo o primeiro dia do grupo, hcomo as horas desse grupo, lcomo o último dia do grupo e wpara quando o último grupo volta ao início da semana. Quando uma incompatibilidade é encontrada, o grupo anterior é impresso, a menos que o empacotamento semanal esteja em vigor. Finalmente, quando todos os dias são processados, o último grupo é ajustado para qualquer quebra de semana e se todas as horas foram iguais antes de serem exibidas. 0é usado como um espaço reservado porque cadeias vazias custam mais bytes para comparar no lote.


2

Geléia , 87 84 80 75 bytes

  • 4bytes com a ajuda de @Dennis (corrigido um hack que eu usei com o 'quick, "flat")

Certeza de que existe uma maneira melhor, mas por enquanto:

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

TryiItOnline

Quão?

            “ḅạṄ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)

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)

Recebe a entrada como uma matriz e gera para o console em linhas separadas. Esta é quase exatamente uma porta da minha resposta em lote; fagora o padrão é uma seqüência vazia, claro, enquanto eu também pode usar como padrão le wpara 'sun'(usando um valor de sentinela me salvou 3 bytes em Batch porque eu era capaz de mesclar a inicialização no set/a).


1

Bacon , 514 496 455 bytes

O programa BASIC abaixo é mostrado com seu recuo. Mas sem o recuo, ele consiste em 455 bytes.

A idéia é usar os horários como índices para uma matriz associativa. Então, cada dia representa um pouco: segunda-feira = bit 0, terça-feira = bit 1, quarta-feira = bit 2 e assim por diante. Os valores reais para os membros da matriz associativa são calculados pelos respectivos bits dos dias usando um OR binário.

Depois disso, é uma questão de verificar quantos bits consecutivos estão presentes nos membros da matriz associativa, começando com o bit 0.

Caso o bit 0 e também o bit 6 estejam configurados, há uma quebra de semana. Nesse caso, comece a procurar o início da próxima sequência de bits, memorizando esta posição inicial. Imprima o restante das seqüências e, assim que o bit 6 for atingido, o intervalo de dias deverá terminar com a posição memorizada anteriormente.

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 as seguintes chamadas para chamar o 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")

Saída :

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.