Contar os intervalos de tempo

17

Inspirado em um cenário da vida real, ao qual solicitei uma resposta aqui: /superuser/1312212/writing-a-formula-to-count-how-many-times-each-date- aparece em um conjunto de datas

Dada uma matriz de intervalos de tempo (ou pares de datas de início e término), produza uma contagem de quantos intervalos de tempo abrangem todos os dias, para todos os dias no intervalo total.

Por exemplo:

  #      Start      End
  1    2001-01-01 2001-01-01
  2    2001-01-01 2001-01-03
  3    2001-01-01 2001-01-02
  4    2001-01-03 2001-01-03
  5    2001-01-05 2001-01-05

Dados os dados acima, os resultados devem ser os seguintes:

2001-01-01: 3 (Records 1,2,3)
2001-01-02: 2 (Records 2,3)
2001-01-03: 2 (Records 2,4)
2001-01-04: 0
2001-01-05: 1 (Record 5)

Você só precisa exibir as contagens para cada dia (em ordem, classificadas da mais antiga para a mais nova); não em quais registros eles aparecem.

Você pode assumir que cada período de tempo contém apenas datas, não horários; e assim dias inteiros são sempre representados.

I / O

A entrada pode ser qualquer formato que represente um conjunto de intervalos de tempo - portanto, um conjunto de pares de horários ou uma coleção de objetos (integrados) que contêm datas de início e término. A data e hora são limitadas entre 1901 e 2099, como é normal para os desafios do PPCG.

Você pode assumir que a entrada é pré-classificada da maneira que desejar (especifique na sua resposta). As datas de entrada são inclusivas (portanto, o intervalo inclui todas as datas de início e término).

Você também pode assumir que, das duas datas em um determinado intervalo, a primeira será mais antiga ou igual à segunda (ou seja, você não terá um período negativo).

A saída é uma matriz que contém a contagem para cada dia, da mais antiga à mais recente na entrada quando classificada por Data de Início.

Portanto, a saída para o exemplo acima seria {3,2,2,0,1}

É possível que alguns dias não sejam incluídos em nenhum intervalo de tempo; nesse caso, a 0saída será para essa data.

Critérios Vencedores

Isso é código-golfe, então os bytes mais baixos vencem. Aplicam-se exclusões usuais

Exemplo de pseudo-algoritmo

For each time range in input
    If start is older than current oldest, update current oldest
    If end is newer than current newest, update current newest
End For
For each day in range oldest..newest
   For each time range
       If timerange contains day
            add 1 to count for day
End For
Output count array

Outros algoritmos para obter o mesmo resultado são bons.

simonalexander2005
fonte
3
É necessária uma matriz de números inteiros ou podemos retornar outra coisa, digamos, um dicionário com chaves a cada data? Se pudermos retornar um dicionário, podemos omitir datas que não estão em nenhum dos intervalos de tempo?
JungHwan
1
podemos considerar a entrada como duas listas, uma com datas de início e outra com datas de término correspondentes?
Giuseppe
Sim, todas essas coisas estão bem, exceto a omissão de uma data - eu digo explicitamente que 0 deve ser emitido nesse caso
simonalexander2005
3
Posso perguntar por que 0deveria estar em um dicionário? Parece apenas forçar o usuário a iterar de min(input)para max(input), o que não parece acrescentar nada ao cerne do desafio (intervalos de tempo de computação).
JungHwan
2
@JungHwanMin Eu acho que não altera; mas porque eu o tinha explicitamente nas especificações quando o
publiquei

Respostas:

3

APL (Dyalog Unicode) , SBCS de 32 bytes

Programa completo. Solicita ao stdin uma lista de pares de números de datas internacionais (como o Excel e o MATLAB usam). A lista e os pares podem ser fornecidos em qualquer ordem, por exemplo (Fim, Início). Imprime a lista de contagens para stdout.

¯1+⊢∘≢⌸(R,⊢)∊(R←⌊/,⌊/+∘⍳⌈/-⌊/)¨⎕Experimente online!

Se isso for inválido, uma lista de pares (YMD) poderá ser convertida para 21 bytes adicionais, totalizando 53:

¯1+⊢∘≢⌸(R,⊢)∊(R⌊/,⌊/+∘⍳⌈/-⌊/)¨{2⎕NQ#'DateToIDN'⍵}¨¨⎕Experimente online!


 console de prompt para entrada avaliada

( Aplique a seguinte função tácita a cada par

⌊/ o mínimo (lit. min-redução), ou seja, a data de início

⌈/- a data máxima (isto é, data final) menos

⌊/+∘⍳ a data de início mais o intervalo de 1 a

⌊/, a data de início anexada a essa

R← atribuir esta função a R(para R ange)

ε nlist (achatar) a lista de intervalos em uma única lista

() Aplique a seguinte função tácita a isso:

R,⊢ o resultado da aplicação R(ou seja, o período) seguido do argumento
  (isso garante que cada data no intervalo seja representada pelo menos uma vez e que as datas apareçam na ordem classificada)

 Para cada par de dados únicos (data, seus índices de ocorrência na entrada), faça:

⊢∘≢ ignore a data real em favor da contagem de índices

¯1+ adicione -1 a essas notas (porque adicionamos um de cada data no intervalo)

Adão
fonte
9

JavaScript (ES6), 85 bytes

Recebe entrada como uma lista de Datepares. Espera que a lista seja classificada por data de início. Retorna uma matriz de números inteiros.

f=(a,d=+a[0][0])=>[a.map(([a,b])=>n+=!(r|=d<b,d<a|d>b),r=n=0)|n,...r?f(a,d+864e5):[]]

Experimente online!

ou 84 bytes, se pudermos usar timestamps JS como entrada (como sugerido por @Shaggy)

Arnauld
fonte
Ah, nozes!
Shaggy
Salvar um byte, tendo os valores primitivos como entrada: TIO
Shaggy
7

JavaScript, 75 73 bytes

Recebe a entrada como uma matriz classificada de matrizes de pares primitivos de datas, gera um objeto em que as chaves são as primitivas de cada data e os valores que são contadas nessas datas nos intervalos.

a=>a.map(g=([x,y])=>y<a[0][0]||g([x,y-864e5],o[y]=~~o[y]+(x<=y)),o={})&&o

Tente


Eu estava trabalhando nessa versão de 60 bytes, até que foi confirmado que as datas que não aparecem em nenhum dos intervalos devem ser incluídas, então atualizei-a rapidamente para a solução acima.

a=>a.map(g=([x,y])=>x>y||g([x+864e5,y],o[x]=-~o[x]),o={})&&o

Experimente on-line (ou com datas legíveis por humanos na saída )

Shaggy
fonte
Parece que o ES6 define uma ordem de chave para objetos JS ( stackoverflow.com/a/31102605/8127 ), basicamente, ordem de inserção para chaves de string e símbolo (e os Nodejs do TIO parecem seguir isso: tinyurl.com/ybjqtd89 ). E, em geral, minha opinião é que um detalhe de implementação (que é o objetivo aqui) não deve ditar a interpretação das regras de desafio, mas vou esperar pelo post do Meta.
sundar - Restabelece Monica
6

Oitava , 63 bytes

@(x)histc(t=[cellfun(@(c)c(1):c(2),x,'un',0){:}],min(t):max(t))

Experimente online!

Agora isso foi feio!

Explicação:

Aceita a entrada como uma matriz de datenumelementos da célula (ou seja, uma string "2001-01-01"convertida em um valor numérico, com a seguinte aparência:

{[d("2001-01-01") d("2001-01-01")]
[d("2001-01-01") d("2001-01-03")]
[d("2001-01-01") d("2001-01-02")]
[d("2001-01-03") d("2001-01-03")]
[d("2001-01-05") d("2001-01-05")]};

onde d()representa a função datenum. Em seguida, usamos cellfunpara criar células com os intervalos da primeira coluna à segunda para cada uma dessas linhas. Concatenamos esses intervalos horizontalmente, para termos um vetor horizontal longo com todas as datas.

Em seguida, criamos um histograma usando histcesses valores, com compartimentos fornecidos pelo intervalo entre a data mais baixa e a mais alta.

Stewie Griffin
fonte
5

R , 75 bytes

function(x,u=min(x):max(x))rowSums(outer(u,x[,1],">=")&outer(u,x[,2],"<="))

Experimente online!

Input é uma matriz cuja primeira coluna é Start e a segunda coluna é End. Assume Início <= Final, mas não exige que as datas de início sejam classificadas.

JayCe
fonte
Isso é o máximo que pude tentar replicar a resposta da oitava de Stewie Griffin ... o que estou fazendo de errado?
Jayce
é por causa da maneira como R faz suas caixas hist; você poderia fazer c(-25668,min(x):max(x))desde -25568antes, 1900mas isso acaba sendo mais longo do que a resposta sugerida. Dito isto, há uma maneira melhor de gerar as datas do que apply; Eu tenho um que tem 68 bytes e não encontrei tempo para publicá-lo.
Giuseppe
Ah, não, na verdade, use (min(x)-1):max(x)e deve funcionar como esperado; se você encontrar o applycaminho para gerar as datas, poderá obtê-lo em 63 bytes e amarrar a resposta da oitava.
Giuseppe
@Giuseppe Você deve publicá-la como uma resposta em separado :)
Jayce
posted :-) Eu tenho que admitir, eu estava usando tablee factorantes do que era meu uso original Mappor 68 bytes, mas histé uma abordagem interessante que eu sempre esqueço, provavelmente porque é irritante fazer as caixas da maneira certa (como vimos )
Giuseppe
4

Vermelho , 174 bytes

func[b][m: copy #()foreach[s e]b[c: s
until[m/(c): either none = v: m/(c)[1][v + 1]e < c: c + 1]]c: first sort b
until[print[either none = v: m/(c)[0][v]](last b)< c: c + 1]]

Implementação bastante longa e literal.

Experimente online!

Legível:

f: func [ b ] [
    m: copy #()
    foreach [ s e ] b [
        c: s
        until [
            m/(c): either none = v: m/(c) [ 1 ] [ v + 1 ]   
            e < c: c + 1
        ]      
    ]
    c: first sort b
    until[
        print [ either none = v: m/(c) [ 0 ] [ v ] ]
        ( last b ) < c: c + 1
    ]      
]
Galen Ivanov
fonte
4

Groovy, 142 bytes

{a={Date.parse('yyyy-mm-dd',it)};b=it.collect{a(it[0])..a(it[1])};b.collect{c->b.collect{it}.flatten().unique().collect{it in c?1:0}.sum()}}

O que outras pessoas estão dizendo

Formatado para fora:

 {                                   // Begin Closure
    a={Date.parse('yyyy-mm-dd',it)}; // Create closure for parsing dates, store in a().
    b=it.collect{                    // For each input date pair...
        a(it[0])..a(it[1])           // Parse and create date-range.
    };
    b.collect{                       // For each date range...
        c->
        b.collect{                   // For each individual date for that range...
           it
        }.flatten().unique().collect{ // Collect unique dates.
            it in c?1:0
        }.sum()                      // Occurrence count.
    }
}
Urna de polvo mágico
fonte
4

Python 2 , 114 87 93 bytes

-27 bytes graças a Jonathan Allan
+6 bytes graças a sundar

Recebe entrada como lista de pares de objetos de data e hora.
Supõe que o primeiro par começa com a data mais baixa.

def F(I):
 d=I[0][0]
 while d<=max(sum(I,[])):print sum(a<=d<=b for a,b in I);d+=type(d-d)(1)

Experimente online!

Gambá morto
fonte
daysé o argumento padrão para timedelta.
Jonathan Allan
... na verdade, acho que você pode largar from datetime import*e substituir d+=timedelta(days=1)por, d+=type(d-d)(1)já que as entradas já são dates. 87 bytes
Jonathan Allan
1
Isso parece assumir que o início do primeiro intervalo é a data mais baixa E o final do último intervalo é o mais alto - mas acho que isso às vezes não é possível, mesmo que o OP nos permita obter informações classificadas. Por exemplo. se a entrada é [(2001-01-01, 2001-01-05), (2001-01-02, 2001-01-03)]. A menos que o OP nos permita dividir e reorganizar esses intervalos durante o pré-processamento (o que parece improvável), essa entrada não pode ser processada por esse código corretamente.
sundar - Restabelece Monica
@ Sundar Sim, eu vejo o que você está falando. Atualizei a solução para lidar com isso. Obrigado!
Gambá morto
3

Wolfram Language (Mathematica) , 62 bytes

Lookup[d=DayRange;Counts[Join@@d@@@#],#[[1,1]]~d~#[[-1,1]],0]&

Experimente online!

+35 bytes porque OP especificado que 0deve ser incluído na saída.

Se a omissão de uma entrada em um dicionário fosse permitida, 27 bytes

Counts[Join@@DayRange@@@#]&

Experimente online!

O built-in DayRangeaceita dois DateObjects (ou um equivalente de sequência) e gera uma lista Datesentre essas datas (inclusive).

JungHwan Min
fonte
3

R , 65 bytes 63

function(x)hist(unlist(Map(`:`,x[,1],x[,2])),min(x-1):max(x))$c

Experimente online!

Esta é uma colaboração entre JayCe e eu, portando a resposta de Stewie Griffin para R.

Para citar JayCe:

Input é uma matriz cuja primeira coluna é Start e a segunda coluna é End. Assume Início <= Final, mas não exige que as datas de início sejam classificadas.

Possivelmente, $cé desnecessário, mas não está no espírito do desafio, então eu o incluí.

Giuseppe
fonte
1
Mín (x-1) para 2 bytes?
Jayce
^ Por que eu quero dizer isso
Jayce
@JayCe yes, nice! Eu pretendia voltar a isso mais cedo, mas esqueci.
Giuseppe
3

Powershell, 122 121 118 113 bytes

filter d{0..($_[-1]-($s=$_[0])).Days|%{$s.AddDays($_)}}$c=@{};$args|d|%{++$c.$_};,($c.Keys.Date|sort)|d|%{+$c.$_}

salve-o como count-timespan.ps1. Script de teste:

.\count-timespan.ps1 `
    @([datetime]"2001-01-01", [datetime]"2001-01-01")`
    @([datetime]"2001-01-01", [datetime]"2001-01-03")`
    @([datetime]"2001-01-01", [datetime]"2001-01-02")`
    @([datetime]"2001-01-03", [datetime]"2001-01-03")`
    @([datetime]"2001-01-05", [datetime]"2001-01-05")

Explicação

filter d{                           # define a function with a pipe argument (it's expected that argument is an array of dates)
    0..($_[-1]-($s=$_[0])).Days|%{  # for each integer from 0 to the Days
                                    # where Days is a number of days between last and first elements of the range
                                    # (let $s stores a start of the range)
        $s.AddDays($_)              # output to the pipe a date = first date + number of the current iteration
    }                               # filter returns all dates for each range
}                                   # dates started from first element and ended to last element
$c=@{}                              # define hashtable @{key=date; value=count}
$args|d|%{++$c.$_}                  # count each date in a array of arrays of a date
,($c.Keys.Date|sort)|d|%{+$c.$_}    # call the filter via pipe with the array of sorted dates from hashtable keys

# Trace:
# call d @(2001-01-01, 2001-01-01) @(2001-01-01, 2001-01-03) @(2001-01-01, 2001-01-02) @(2001-01-03, 2001-01-03) @(2001-01-05, 2001-01-05)
# [pipe]=@(2001-01-01, 2001-01-01, 2001-01-02, 2001-01-03, 2001-01-01, 2001-01-02, 2001-01-03, 2001-01-05)
# $c=@{2001-01-03=2; 2001-01-01=3; 2001-01-05=1; 2001-01-02=2}
# call d @(2001-01-01, 2001-01-02, 2001-01-03, 2001-01-05)
# [pipe]=@(2001-01-01, 2001-01-02, 2001-01-03, 2001-01-04, 2001-01-05)
# [output]=@(3, 2, 2, 0, 1)
confuso
fonte
Obrigado! $cnt.Keys.Dateclaro.
Mazzy
-3 bytes: functionsubstituído por scriptblock. códigos de golfe e não de golfe são testados.
Mazzy
-5 bytes: scriptblocksubstituído em filter. A chamada de a filteré mais compacta.
Mazzy
3

J, 43 bytes

(],.[:+/@,"2="{~)&:((>./(]+i.@>:@-)<./)"1),

a entrada é uma lista de pares de números inteiros, em que cada número inteiro é o deslocamento de qualquer dia 0 arbitrário comum.

destroçado

(] ,. [: +/@,"2 ="{~)&:((>./ (] + i.@>:@-) <./)"1) ,

explicação

estrutura é:

(A)&:(B) C
  • C cria um gancho que fornece ao verbo principal A&:Ba entrada à esquerda e a entrada achatada à direita
  • B aka ((>./ (] + i.@>:@-) <./)"1)pega o mínimo e o máximo de uma lista e retorna o intervalo resultante e atua com a classificação 1. portanto, fornece o intervalo total à direita e os intervalos individuais à esquerda.
  • A então usa =with rank "0 _(ou seja, rank of {) para contar quantas vezes cada entrada aparece em qualquer um dos intervalos. finalmente fecha todos os anos com essas contagens.

Experimente online!

Jonah
fonte
2

JavaScript (Node.js) , 80 bytes

(a,u=[])=>a.map(g=([p,q])=>p>q||g([p,q-864e5],u[z=(q-a[0][0])/864e5]=-~u[z]))&&u

Experimente online!

undefinedsignifica zero; O primeiro elemento deve começar o mais cedo

(a,u=[])=>a.map(g=([p,q])=>p>q||g([p,q-1],u[z=(q-a[0][0])/864e5]=-~u[z]))&&u é mais curto se você vir apenas elementos e usar mais pilha

l4m2
fonte
6
Você deve pedir confirmação de que a substituição de outro valor 0é aceitável.
Shaggy
1

Ruby , 70 bytes

->s{f,=s.min;(p s.count{|a,b|(f-a)*(f-b)<=0};f+=86400)until f>s[0][1]}

Experimente online!

Entrada:

Matriz de pares de datas, classificadas por data final decrescente.

GB
fonte
1

R (70)

function(x)(function(.)tabulate(.-min(.)+1))(unlist(Map(seq,x$S,x$E,"d")))

Pressupõe um quadro de dados xcom duas colunas ( Starte Endou possivelmente Se E) com datas (classe Date).

Experimente online

lebatsnok
fonte
Olá, você poderia incluir links TIO (consulte outras respostas) com um exemplo de entrada / saída? Não é uma trapaça incluir um pacote, mas library(magrittr)precisa ser incluído nas contagens de bytes.
Jayce
Também conforme o consenso, os envios precisam ter funções ou programas completos, não trechos, portanto, se você usar uma função cujo único argumento é xsua resposta, começa com function(x)o corpo da função.
Jayce
1

Julia 0,6 , 77 bytes

M->[println(sum(dM[r,1]:M[r,2]for r1:size(M,1)))for dM[1]:max(M...)]

Experimente online!

Inspirado na solução Python da @ DeadPossum .

Recebe entrada como uma matriz, onde cada linha tem duas datas: as datas inicial e final de um intervalo de entrada. Supõe que a entrada tenha a data mais antiga primeiro e que cada linha tenha a data inicial primeiro, mas não assume nenhuma classificação além daquela entre linhas diferentes.


Solução mais antiga:

Julia 0.6 , 124 bytes

R->(t=Dict();[[dkeys(t)?t[d]+=1:t[d]=1 for dg]for gR];[dkeys(t)?t[d]:0 for dmin(keys(t)...):max(keys(t)...)])

Experimente online!

Aceita entrada como uma matriz de períodos. Não assume nenhuma classificação entre os diferentes intervalos na matriz.

sundar - Restabelecer Monica
fonte