计算时间跨度


17

受到现实生活场景的启发,我要求在这里给出答案:https : //superuser.com/questions/1312212/writing-a-formula-to-count-how-many-times-each-date-出现在一组日期中

给定一组时间跨度(或开始日期-结束日期对),输出总范围内所有天每天覆盖多少时间跨度的计数。

例如:

  #      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

根据上述数据,结果应如下所示:

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)

您只需要输出每天的计数(按最旧-最新的顺序排序);而不是它们出现在哪些记录中。

您可以假设每个时间跨度仅包含日期,而不是时间;因此,总是代表着整天。

输入输出

输入可以是表示一组时间跨度的任何格式,因此可以是一组时间对,也可以是一组包含开始日期和结束日期的(内置)对象。日期时间限制在1901年到2099年之间,这是PPCG挑战的正常情况。

您可以假设输入是预排序的,但是可以根据自己的喜好进行输入(在答案中指定)。输入日期包括在内(因此范围包括整个开始日期和结束日期)。

您还可以假定在任何给定范围内的两个日期中,第一个日期将早于或等于第二个日期(即,您将没有负数的日期范围)。

输出是一个数组,其中包含按开始日期排序时输入中从最旧到最新的每一天的计数。

因此,以上示例的输出为 {3,2,2,0,1}

可能在某些时间范围内未包含某些天,在这种情况下,0将输出该日期。

获奖标准

这是代码高尔夫球,因此最低字节为准。通常排除

伪算法示例

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

其他获得相同结果的算法也很好。


3
是否需要整数数组,还是允许我们返回其他内容,比如说一个将每个日期作为键的字典?如果允许我们返回字典,那么我们可以省略不在任何时间跨度内的日期吗?
JungHwan Min

1
我们可以将输入作为两个列表,一个带有开始日期,另一个带有相应的结束日期吗?
朱塞佩

是的,所有这些都很好,但是省略了一个日期-我明确地说在这种情况下应该输出0
simonalexander2005年

3
请问为什么0要在字典中?它似乎仅迫使用户从迭代min(input)max(input),这似乎并没有增加挑战的核心(计算时间)。
JungHwan Min

2
@JungHwanMin我猜它并没有改变;但由于我在发布时明确将其包含在规范中,所以我不想弄乱它,让其他人重做他们的答案
simonalexander2005年

Answers:


3

APL(Dyalog Unicode),32 字节SBCS

完整程序。提示stdin提供一对国际日期编号对(例如Excel和MATLAB使用的)的列表。列表和对都可以以任何顺序给出,例如(结束,开始)。将计数列表打印到标准输出。

¯1+⊢∘≢⌸(R,⊢)∊(R←⌊/,⌊/+∘⍳⌈/-⌊/)¨⎕在线尝试!

如果这是无效的,则可以将(YMD)对的列表转换为另外的21个字节,总计53:

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


 提示输入评估控制台

( 对每对应用以下默认功能

⌊/ 最小(最小减少量),即开始日期

⌈/- 最大值(即结束日期)减去

⌊/+∘⍳ 开始日期加上范围1至

⌊/, 开始日期早于

R← 此函数分配给R(用于ř安格)

ϵ nlist(展平)范围列表成一个列表

(…… ) 对此应用以下默认功能:

R,⊢ 应用R(即日期范围)后跟参数的结果
  (这确保范围内的每个日期至少被表示一次,并且日期按排序顺序显示)

 对于每对唯一的对象(日期,其在输入中的出现索引),请执行以下操作:

⊢∘≢ 忽略实际日期,以利于指数统计

¯1+ 将-1加到这些计数(因为我们在范围内的每个日期之前加上了一个前缀)


9

JavaScript(ES6),85个字节

将输入作为对列表Date。期望列表按开始日期排序。返回整数数组。

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

在线尝试!

84个字节(如果我们可以将JS时间戳记作为输入)(如@Shaggy所建议)



通过将原始值作为输入来保存字节:TIO
Shaggy

7

JavaScript,75 73字节

将输入作为日期图元对数组的排序数组,输出一个对象,其中键是每个日期的图元,值是范围内这些日期的计数。

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

尝试一下


我一直在处理这个60字节的版本,直到确认必须包括所有范围中未出现的日期,然后才将其匆匆更新为上述解决方案。

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

在线尝试(或在输出中输入易于理解的日期


看起来ES6确实为JS对象定义了键顺序(stackoverflow.com/a/31102605/8127),基本上是字符串和符号键的插入顺序(TIO的Nodejs似乎遵循该顺序:tinyurl.com/ybjqtd89)。总的来说,我的观点是,实现细节(这就是这里的对象)不应决定对挑战规则的解释,但我将等待Meta帖子。
sundar-恢复莫妮卡

6

八度,63字节

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

在线尝试!

现在那太丑了!

说明:

将输入作为datenum元素的单元格数组(即,将字符串"2001-01-01"转换为数值,如下所示:

{[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()函数在哪儿datenum。然后cellfun,我们使用这些行中的每一行创建单元格,其范围从第一列到第二列。我们将这些范围水平连接起来,这样我们就得到了包含所有日期的长水平向量。

然后,我们使用histc这些值创建直方图,并通过最低日期和最高日期之间的范围给出区间。


5

R,75字节

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

在线尝试!

输入是一个矩阵,其第一列为开始,第二列为结束。假定开始<=结束,但不需要对开始日期进行排序。


是据我能去试图复制由Stewie新八度音的答案......我究竟做错了什么?
JayCe

这是因为R在其中进行垃圾箱处理的方式hist;您可以执行此操作,c(-25668,min(x):max(x))因为此-25568操作早1900于此,但最终比您建议的答案更长。话虽这么说,还有一种更好的方法来生成日期apply:我有一个68字节的文件,只是我自己没有时间发布它。
朱塞佩

啊,不,实际上是使用(min(x)-1):max(x),它应该按预期工作。然后,如果您找到apply生成日期的方法,则可以将其取为63字节,并绑定八度音阶答案。
朱塞佩

@Giuseppe您应该将其发布为单独的答案:)
JayCe

发布 :-)我必须承认,我一直在使用tablefactor在此之前我最初使用的Map是68个字节,但这hist是一种我经常忘记的简洁方法,可能是因为将垃圾箱正确放置很烦人(如我们所见) )
朱塞佩

4

红色,174字节

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

相当长的文字实现。

在线尝试!

可读性:

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

4

Groovy,142个字节

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

格式化:

 {                                   // 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.
    }
}

4

Python 2中114个 87 93字节

-27字节归功于Jonathan Allan,
+ 6字节归功于sundar

将输入作为日期时间对象对列表。
假定第一对从最低日期开始。

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)

在线尝试!


days是的默认参数timedelta
乔纳森·艾伦

...事实上,我认为您可以删除from datetime import*和替换为d+=timedelta(days=1)d+=type(d-d)(1)因为输入已经date是s。87位元组
Jonathan Allan

1
这似乎是假设第一个范围的开始是最低日期,而最后一个范围的结束是最高日期-但是我认为,即使OP允许我们接受排序的输入,有时也不可能。例如。如果输入为[(2001-01-01, 2001-01-05), (2001-01-02, 2001-01-03)]。除非OP允许我们在预处理期间分割和重新排列这些范围(这似乎不太可能),否则此代码无法正确处理此输入。
sundar-恢复莫妮卡

@sundar是的,我明白您在说什么。我已经更新了解决方案来解决这个问题。谢谢!
Dead Possum

3

Wolfram语言(Mathematica),62字节

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

在线尝试!

+35个字节,因为OP指定0必须在输出中包含该OP 。

如果省略字典中的条目是允许的,则为27个字节

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

在线尝试!

内置DayRange函数接受两个DateObjects(或等效的字符串),并输出Dates这些日期之间(包括两个日期)的列表。


3

R65 63字节

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

在线尝试!

这是JayCe与我之间的合作,传达了Stewie Griffin的回答到R。

引用JayCe:

输入是一个矩阵,其第一列为开始,第二列为结束。假定开始<=结束,但不需要对开始日期进行排序。

可能$c是不必要的,但它并不是本着挑战的精神,因此已将其包括在内。


1
Min(x-1)2个字节?
JayCe

^我指的是这个
JayCe

@JayCe是的,很好!我本想早点回来,但我忘了。
朱塞佩

3

Powershell,122 121 118 113字节

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

将其另存为count-timespan.ps1。测试脚本:

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

说明

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)

谢谢!$cnt.Keys.Date当然。
mazzy

-3个字节:function替换为scriptblock。高尔夫球码和非高尔夫球码均经过测试。
mazzy

-5字节:scriptblock替换为filter。调用a filter更紧凑。
mazzy

3

J,43个字节

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

输入是整数对的列表,其中每个整数是相对于任意任意普通0天的偏移量。

不打高尔夫球

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

说明

结构是:

(A)&:(B) C
  • C创建一个钩子,为主动词A&:B的左侧输入,右侧的输入扁平化
  • Baka ((>./ (] + i.@>:@-) <./)"1)取列表的最小值和最大值并返回结果范围,并以等级1起作用。因此,它在右侧给出总范围,在左侧给出单个范围。
  • 然后=,A 与等级一起使用"0 _(即,等级为{)来计算每个输入出现在任何范围内的次数。最终,这些数字每年都会压缩。

在线尝试!


2

JavaScript(Node.js),80字节

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

在线尝试!

undefined表示零;第一个元素应该最早开始

(a,u=[])=>a.map(g=([p,q])=>p>q||g([p,q-1],u[z=(q-a[0][0])/864e5]=-~u[z]))&&u 如果您仅看到元素并使用更多堆栈,则长度会更短


6
您应该要求确认是否可以用另一个值代替0
粗野的

1

红宝石,70个字节

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

在线尝试!

输入:

日期对数组,按结束日期降序排列。


1

R(70)

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

假定一个数据框架x具有两列(Start和(End或可能SE),并带有日期(类Date))。

在线尝试


嗨,您可以在输入/输出示例中包含TIO链接(请参阅其他答案)吗?包含一个包并不是在作弊,而是library(magrittr)需要包含在字节数中。
JayCe

同样,按照共识,提交的内容必须是完整的功能或程序,而不是摘要,因此,如果您使用的函数的唯一参数是x答案function(x),则其开头应为函数主体。
JayCe

1

朱莉娅0.6,77字节

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

在线尝试!

受@DeadPossum的Python解决方案启发。

将输入作为矩阵,其中每行都有两个日期:输入范围的开始和结束日期。假定输入的最早日期是最早的,并且每一行的起始日期是第一,但是假定除了在不同行之间的排序之外,没有其他排序。


较旧的解决方案:

朱莉娅 0.6,124字节

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

在线尝试!

接受输入作为日期范围的数组。不假设数组中不同范围之间有任何排序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.