Comptez les délais

17

Inspiré d'un scénario réel, auquel j'ai demandé une réponse ici: /superuser/1312212/writing-a-formula-to-count-how-many-times-each-date- apparaît dans un ensemble de dates

Étant donné un tableau d'intervalles de temps (ou de paires startdate-enddate), affichez un nombre de périodes couvrant chaque jour, pour tous les jours de la plage totale.

Par exemple:

  #      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

Compte tenu des données ci-dessus, les résultats devraient être les suivants:

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)

Vous avez seulement besoin de sortir les comptes pour chaque jour (dans l'ordre, triés du plus ancien au plus récent); pas dans quels enregistrements ils apparaissent.

Vous pouvez supposer que chaque intervalle de temps contient uniquement des dates, pas des heures; et ainsi des jours entiers sont toujours représentés.

E / S

L'entrée peut être n'importe quel format représentant un ensemble d'intervalles de temps - donc soit un ensemble de paires d'heures, soit une collection d'objets (intégrés) contenant des dates de début et de fin. Les dates-heures sont limitées entre 1901 et 2099, comme c'est normal pour les défis PPCG.

Vous pouvez supposer que l'entrée est pré-triée comme vous le souhaitez (spécifiez dans votre réponse). Les dates d'entrée sont inclusives (donc la plage comprend l'ensemble des dates de début et de fin).

Vous pouvez également supposer que, parmi les deux dates d'une plage donnée, la première sera plus ancienne ou égale à la seconde (c'est-à-dire que vous n'aurez pas de plage de dates négative).

La sortie est un tableau contenant le nombre pour chaque jour, du plus ancien au plus récent dans l'entrée lorsqu'il est trié par date de début.

Ainsi, la sortie de l'exemple ci-dessus serait {3,2,2,0,1}

Il est possible que certains jours ne soient inclus dans aucune plage horaire, auquel cas la 0sortie est effectuée pour cette date.

Critères gagnants

C'est le code-golf, donc les octets les plus bas gagnent. Les exclusions habituelles s'appliquent

Exemple de pseudo-algorithme

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

D'autres algorithmes pour arriver au même résultat sont très bien.

simonalexander2005
la source
3
Un tableau d'entiers est-il requis, ou sommes-nous autorisés à renvoyer autre chose, par exemple un dictionnaire avec des clés pour chaque date? Si nous sommes autorisés à renvoyer un dictionnaire, pouvons-nous alors omettre des dates qui ne figurent dans aucune des plages horaires?
JungHwan Min
1
pouvons-nous prendre la saisie comme deux listes, une avec les dates de début et l'autre avec les dates de fin correspondantes?
Giuseppe
Oui, toutes ces choses vont bien, sauf en omettant une date - je dis explicitement que 0 devrait être
sorti
3
Puis-je demander pourquoi 0devrait être dans un dictionnaire? Cela semble seulement forcer l'utilisateur à parcourir de min(input)à max(input), ce qui ne semble rien ajouter au cœur du défi (temps de calcul).
JungHwan Min
2
@JungHwanMin Je suppose que cela ne le modifie pas; mais parce que je l'avais explicitement dans la spécification quand je l'ai posté, je ne veux pas aller jouer avec elle et faire refaire sa réponse à quelqu'un d'autre
simonalexander2005

Réponses:

3

APL (Dyalog Unicode) , 32 octets SBCS

Programme complet. Demande à stdin une liste de paires de numéros de date internationaux (comme ce qu'utilisent Excel et MATLAB). La liste et les paires peuvent être données dans n'importe quel ordre, par exemple (Fin, Début). Imprime la liste des décomptes vers la sortie standard.

¯1+⊢∘≢⌸(R,⊢)∊(R←⌊/,⌊/+∘⍳⌈/-⌊/)¨⎕Essayez-le en ligne!

Si cela n'est pas valide, une liste de paires (YMD) peut être convertie pour 21 octets supplémentaires, pour un total de 53:

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


 console d'invite pour l'entrée évaluée

( Appliquer la fonction tacite suivante à chaque paire

⌊/ le minimum (lit. min-réduction), c'est-à-dire la date de début

⌈/- le maximum (c'est-à-dire la date de fin) moins

⌊/+∘⍳ la date de début plus la plage de 1 à celle

⌊/, la date de début précédait celle

R← affecter cette fonction à R(pour R ange)

ε nlist (aplatir) la liste des gammes en une seule liste

()  Appliquer la fonction tacite suivante à cela:

R,⊢ le résultat de l'application R(c'est-à-dire la plage de dates) suivi de l'argument
   (cela garantit que chaque date de la plage est représentée au moins une fois et que les dates apparaissent dans l'ordre trié)

 Pour chaque paire d'unique (date, ses indices d'occurrence en entrée), faites:

⊢∘≢ ignorer la date réelle en faveur du décompte des indices

¯1+ ajoutez -1 à ces décomptes (car nous avons ajouté une de chaque date dans la plage)

Adam
la source
9

JavaScript (ES6), 85 octets

Prend la saisie sous forme de liste de Datepaires. Attend que la liste soit triée par date de début. Renvoie un tableau d'entiers.

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):[]]

Essayez-le en ligne!

ou 84 octets si nous pouvons prendre les horodatages JS en entrée (comme suggéré par @Shaggy)

Arnauld
la source
Enregistrer un octet en prenant les valeurs primitives en entrée: TIO
Shaggy
7

JavaScript, 75 73 octets

Prend les entrées sous la forme d'un tableau trié de tableaux de paires de primitives de date, génère un objet dont les clés sont les primitives de chaque date et les valeurs, le nombre de ces dates dans les plages.

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

Essayez-le


Je travaillais sur cette version de 60 octets jusqu'à ce qu'il soit confirmé que les dates qui n'apparaissent dans aucune des plages doivent être incluses, donc mis à jour à la hâte vers la solution ci-dessus.

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

Essayez-le en ligne (ou avec des dates lisibles par l'homme dans la sortie )

Hirsute
la source
Il semble que ES6 définisse un ordre de clé pour les objets JS ( stackoverflow.com/a/31102605/8127 ), un ordre d'insertion de base pour les clés de chaîne et de symbole (et les Nodejs de TIO semblent suivre cela: tinyurl.com/ybjqtd89 ). Et en général, mon avis est qu'un détail d'implémentation (qui est l'objet ici) ne devrait pas dicter l'interprétation des règles de contestation, mais j'attendrai le message Meta.
sundar
6

Octave , 63 octets

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

Essayez-le en ligne!

Maintenant, c'était moche!

Explication:

Prend l'entrée comme un tableau de cellules d' datenuméléments (c'est-à-dire une chaîne "2001-01-01"convertie en une valeur numérique, ressemblant à ceci:

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

d()est la fonction datenum. Nous utilisons ensuite cellfunpour créer des cellules avec les plages de la première colonne à la seconde pour chacune de ces lignes. Nous concaténons ces plages horizontalement, de sorte que nous avons un long vecteur horizontal avec toutes les dates.

Nous créons ensuite un histogramme à l'aide histcde ces valeurs, avec des cases données par la plage entre la date la plus basse et la date la plus élevée.

Stewie Griffin
la source
5

R , 75 octets

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

Essayez-le en ligne!

L'entrée est une matrice dont la première colonne est Début et la deuxième colonne est Fin. Suppose Début <= Fin mais ne nécessite pas de tri des dates de début.

JayCe
la source
C'est aussi loin que j'ai pu essayer de reproduire la réponse d'Octave de Stewie Griffin ... qu'est-ce que je fais mal?
JayCe
c'est à cause de la façon dont R fait ses poubelles hist; vous pourriez faire c(-25668,min(x):max(x))depuis -25568avant, 1900mais cela finit par être plus long que votre réponse suggérée. Cela étant dit, il existe une meilleure façon de générer les dates que apply; J'en ai un qui fait 68 octets et je n'ai tout simplement pas trouvé le temps de le poster moi-même.
Giuseppe
Ah, non, en fait, utilisez (min(x)-1):max(x)et cela devrait fonctionner comme prévu; alors si vous pouvez trouver le applymoyen de générer les dates, vous pouvez obtenir ceci à 63 octets et lier la réponse Octave.
Giuseppe
@Giuseppe Vous devez le poster comme une réponse distincte :)
JayCe
Posté :-) Je dois admettre que j'utilisais tableet factoravant ce qui était mon utilisation d'origine Mappour 68 octets, mais histc'est une approche soignée que j'oublie toujours, probablement parce que c'est ennuyeux d'obtenir les bacs juste à droite (comme nous l'avons vu )
Giuseppe
4

Rouge , 174 octets

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]]

Implémentation assez longue et littérale.

Essayez-le en ligne!

Lisible:

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
la source
4

Groovy, 142 octets

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

La

Formaté:

 {                                   // 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.
    }
}
Urne de poulpe magique
la source
4

Python 2 , 114 87 93 octets

-27 octets grâce à Jonathan Allan
+6 octets grâce à Sundar

Prend l'entrée sous forme de liste de paires d'objets datetime.
Suppose que la première paire commence par la date la plus basse.

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)

Essayez-le en ligne!

Possum mort
la source
daysest l'argument par défaut de timedelta.
Jonathan Allan
... en fait, je pense que vous pouvez supprimer le from datetime import*et remplacer d+=timedelta(days=1)par d+=type(d-d)(1)puisque les entrées sont déjà dates. 87 octets
Jonathan Allan
1
Cela semble supposer que le début de la première plage est la date la plus basse ET la fin de la dernière plage est la plus élevée - mais je pense que ce n'est parfois pas possible même si l'OP nous permet de prendre une entrée triée. Par exemple. si l'entrée est [(2001-01-01, 2001-01-05), (2001-01-02, 2001-01-03)]. À moins que OP ne nous permette de diviser et de réorganiser ces plages pendant le prétraitement (ce qui semble peu probable), cette entrée ne peut pas être traitée correctement par ce code.
sundar
@sundar Oui, je vois de quoi vous parlez. J'ai mis à jour la solution pour gérer cela. Merci!
Dead Possum
3

Wolfram Language (Mathematica) , 62 octets

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

Essayez-le en ligne!

+35 octets car OP a spécifié qu'il 0doit être inclus dans la sortie.

Si l'omission d'une entrée dans un dictionnaire était autorisée, 27 octets

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

Essayez-le en ligne!

La fonction intégrée DayRangeaccepte deux DateObjects (ou une chaîne équivalente) et affiche une liste d' Datesentre ces dates (inclus).

JungHwan Min
la source
3

R , 65 63 octets

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

Essayez-le en ligne!

Il s'agit d'une collaboration entre JayCe et moi-même, portant la réponse de Stewie Griffin sur R.

Pour citer JayCe:

L'entrée est une matrice dont la première colonne est Début et la deuxième colonne est Fin. Suppose Début <= Fin mais ne nécessite pas de tri des dates de début.

C'est peut-être $cinutile, mais ce n'est pas tout à fait dans l'esprit du défi, je l'ai donc inclus.

Giuseppe
la source
1
Min (x-1) pour 2 octets?
JayCe
^ Par lequel je veux dire ceci
JayCe
@JayCe oui, sympa! Je voulais y revenir plus tôt mais j'ai oublié.
Giuseppe
3

Powershell, 122 121 118 113 113 octets

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

enregistrez-le sous count-timespan.ps1. Script de test:

.\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")

Explication

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)
mazzy
la source
Merci! $cnt.Keys.Datebien sûr.
mazzy
-3 octets: functionremplacé par scriptblock. les codes golfés et non golfés sont testés.
mazzy
-5 octets: scriptblockremplacé le filter. L'appel d'un filterest plus compact.
mazzy
3

J, 43 octets

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

l'entrée est une liste de paires d'entiers, où chaque entier est le décalage de tout 0 jour arbitraire commun.

non golfé

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

explication

la structure est:

(A)&:(B) C
  • C crée un crochet qui donne au verbe principal A&:Bl'entrée à gauche et l'entrée aplatie à droite
  • B aka ((>./ (] + i.@>:@-) <./)"1)prend le min et le max d'une liste et renvoie la plage résultante, et agit avec le rang 1. Par conséquent, il donne la plage totale à droite et les plages individuelles à gauche.
  • A utilise ensuite = avec rang "0 _(c'est-à-dire rang de {) pour compter le nombre de fois que chaque entrée apparaît dans l'une des plages. enfin, il zippe chaque année avec ces chiffres.

Essayez-le en ligne!

Jonas
la source
2

JavaScript (Node.js) , 80 octets

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

Essayez-le en ligne!

undefinedsignifie zéro; Le premier élément doit commencer le plus tôt

(a,u=[])=>a.map(g=([p,q])=>p>q||g([p,q-1],u[z=(q-a[0][0])/864e5]=-~u[z]))&&u est plus court si vous ne voyez que des éléments et utilisez plus de pile

l4m2
la source
6
Vous devez demander confirmation que la substitution d'une autre valeur pour 0est acceptable.
Shaggy
1

Rubis , 70 octets

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

Essayez-le en ligne!

Contribution:

Tableau de paires de dates, triées par date de fin décroissante.

GB
la source
1

R (70)

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

Suppose un bloc de données xavec deux colonnes ( Startet Endou éventuellement Set E) avec des dates (classe Date).

Essayez-le en ligne

lebatsnok
la source
Salut, pourriez-vous inclure des liens TIO (voir les autres réponses) avec un exemple d'entrée / sortie? Ce n'est pas de la triche d'inclure un package, mais library(magrittr)doit être inclus dans le nombre d'octets.
JayCe
De plus, selon le consensus, les soumissions doivent être des fonctions ou des programmes complets, pas des extraits, donc si vous optez pour une fonction dont le seul argument est xvotre réponse commence par function(x)le corps de la fonction.
JayCe
1

Julia 0,6 , 77 octets

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

Essayez-le en ligne!

Inspiré par @ DeadPossum's solution Python de .

Prend l'entrée comme une matrice, où chaque ligne a deux dates: les dates de début et de fin d'une plage d'entrée. Suppose que l'entrée a la date la plus ancienne en premier et que chaque ligne a la date de début en premier, mais ne suppose aucun tri au-delà de celui entre les différentes lignes.


Solution plus ancienne:

Julia 0,6 , 124 octets

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)...)])

Essayez-le en ligne!

Accepte l'entrée comme un tableau de plages de dates. N'assume aucun tri parmi les différentes plages du tableau.

Sundar - Rétablir Monica
la source