시간 간격 계산


17

/superuser/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)

매일 카운트 만 출력하면됩니다 (순서대로 정렬). 어떤 레코드에 표시되지 않습니다.

각 시간 범위에는 시간이 아닌 날짜 만 포함되어 있다고 가정 할 수 있습니다. 그래서 하루 종일 항상 표현됩니다.

I / O

입력 은 일련의 시간 범위를 나타내는 모든 형식이 될 수 있습니다. 따라서 일련의 시간 쌍 또는 시작 날짜와 종료 날짜를 포함하는 (기본 제공) 개체 모음입니다. PPCG 챌린지에서와 같이 날짜-시간은 1901에서 2099 사이로 제한됩니다.

입력이 미리 정렬되어 있다고 가정 할 수 있습니다 (답변에 지정하십시오). 입력 날짜가 포함되므로 범위에 시작 날짜와 종료 날짜가 모두 포함됩니다.

또한 특정 범위의 두 날짜 중 첫 번째 날짜가 두 번째 날짜보다 오래되거나 같다고 가정 할 수 있습니다 (예 : 음수 날짜 범위가 없음).

출력 은 시작 날짜순으로 정렬 할 때 입력에서 가장 오래된 것부터 가장 새로운 것까지 매일의 수를 포함하는 배열입니다.

따라서 위 예제의 출력은 {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 2016

2
@JungHwanMin 나는 그것을 변경하지 않는 것 같아요; 내가 그것을 게시했을 때 명시 적으로 사양에 있었기 때문에, 나는 다른 그들의 대답은 다시 그와 메이크업의 사람과 장난 가고 싶지 않아
simonalexander2005

답변:


3

APL (Dyalog Unicode) , 32 바이트 SBCS

전체 프로그램. 국제 날짜 번호 쌍 목록 (예 : Excel 및 MATLAB이 사용하는 것과 같은)을 묻습니다. 리스트와 페어는 모두 (End, Start)와 같은 순서로 주어질 수 있습니다. 카운트 목록을 stdout에 인쇄합니다.

¯1+⊢∘≢⌸(R,⊢)∊(R←⌊/,⌊/+∘⍳⌈/-⌊/)¨⎕온라인으로 사용해보십시오!

이것이 유효하지 않은 경우, (YMD) 쌍의 목록을 추가로 21 바이트로 변환 할 수 있습니다 (총 53 개).

¯1+⊢∘≢⌸(R,⊢)∊(R⌊/,⌊/+∘⍳⌈/-⌊/)¨{2⎕NQ#'DateToIDN'⍵}¨¨⎕온라인으로 사용해보십시오!


 평가 된 입력을위한 프롬프트 콘솔

( 각 쌍에 다음의 암묵적 기능을 적용하십시오

⌊/ 최소 (최소 최소 감소), 즉 시작 날짜

⌈/- 최대 값 (즉, 종료 날짜)에서

⌊/+∘⍳ 시작일에 1에서 1까지의 범위

⌊/, 앞에 추가 된 시작 날짜

R← 이 기능을 할당 R(위한 R의 앤지)

ε NLIST (패턴 화 된) 하나의 목록으로 광범위의 목록

() 그것에 다음의 암묵적 기능을 적용하십시오 :

R,⊢ 적용 결과 R(예 : 날짜 범위)와 인수
  (범위 내 각 날짜가 적어도 한 번 표시되고 날짜가 정렬 된 순서로 표시됨)

 고유 한 각 쌍 (날짜, 입력에서 발생하는 지표)에 대해 다음을 수행하십시오.

⊢∘≢ 인덱스 집계에 찬성하여 실제 날짜를 무시하십시오.

¯1+ 해당 키에 -1을 더합니다 (범위에서 각 날짜 중 하나를 앞에 추가했기 때문에)


9

자바 스크립트 (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):[]]

온라인으로 사용해보십시오!

또는 @Shaggy에서 제안한대로 JS 타임 스탬프를 입력으로 사용할 수있는 경우 84 바이트



기본 값을 입력으로 사용하여 바이트를 저장하십시오. TIO
Shaggy

7

자바 스크립트, 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 )를 정의 하는 것처럼 보입니다 . 그리고 일반적으로 필자의 의견은 구현 세부 사항 (여기서는 객체가 무엇인지)이 챌린지 규칙의 해석을 지시해서는 안되지만 메타 게시물을 기다릴 것입니다.
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],"<="))

온라인으로 사용해보십시오!

입력은 첫 번째 열이 시작이고 두 번째 열이 종료 인 행렬입니다. Start <= End를 가정하지만 시작 날짜를 정렬하지 않아도됩니다.


이것은 Stewie Griffin의 Octave 답변을 복제하려고 시도 할 수있는 한 ... 내가 뭘 잘못하고 있습니까?
JayCe

그것은 R이 빈을 처리하는 방식 때문입니다 hist. 당신은 할 수 c(-25668,min(x):max(x))있기 때문에 -25568이전 인 1900만 이상 제안 대답보다 더 되 고이 종료된다. 즉, 날짜를 생성하는 것보다 더 나은 방법이 있습니다 apply. 나는 68 바이트에있는 것을 가지고 있으며 그것을 직접 게시 할 시간을 찾지 못했습니다.
주세페

아, 실제로는 사용하지 않으며 (min(x)-1):max(x)예상대로 작동합니다. 그런 다음 apply날짜를 생성하지 않는 방법을 찾으면 63 바이트로 옥타브 응답을 묶을 수 있습니다.
주세페

@Giuseppe 당신은 별도의 답변으로 게시해야합니다 :)
JayCe

게시 :-) 인정해야합니다. 사용 table하고 있었고 factor이전 Map에는 68 바이트를 처음 사용 했지만 hist항상 잊어 버린 깔끔한 접근 방식입니다. )
Giuseppe

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

그루비, 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

파이썬 2 , 114 87 93 바이트

Jonathan Allan 덕분에 -27 바이트
sundar 덕분에 +6 바이트

날짜 / 시간 객체 쌍의 목록으로 입력을받습니다.
첫 번째 쌍이 가장 낮은 날짜로 시작한다고 가정합니다.

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.
Jonathan Allan

... 사실 난 당신이 드롭 할 수 있다고 생각 from datetime import*하고 교체 d+=timedelta(days=1)d+=type(d-d)(1)입력이 이미 있기 때문에 date이야. 87 바이트
Jonathan Allan

1
이것은 첫 번째 범위의 시작이 가장 낮은 날짜이고 마지막 범위의 끝이 가장 높은 것으로 가정하지만 OP가 정렬 된 입력을 허용하더라도 때때로 가능하지 않다고 생각합니다. 예를 들어. 입력되면 [(2001-01-01, 2001-01-05), (2001-01-02, 2001-01-03)]. OP가 전처리 과정에서 이러한 범위를 분할하고 재 배열 할 수 없다면 (아마 보이지는 않지만)이 입력으로이 입력을 제대로 처리 할 수 ​​없습니다.
sundar-복 직원 모니카

@ sundar 예, 당신이 말하는 것을 봅니다. 이 문제를 해결하기 위해 솔루션을 업데이트했습니다. 감사!
Dead Possum 2018 년

3

Wolfram Language (Mathematica) , 62 바이트

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

온라인으로 사용해보십시오!

OP가 지정 0되어 출력에 포함되어야 하므로 +35 바이트

사전에서 항목을 생략 할 수 있으면 27 바이트

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

온라인으로 사용해보십시오!

내장 DayRange 은 두 개의 DateObject(또는 동등한 문자열)을 허용하고 Dates해당 날짜 사이 의 목록을 포함합니다 (포함).


3

R , 65 63 바이트

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

온라인으로 사용해보십시오!

이것은 JayCe 와 나 자신 의 협업 이며, 포팅 Stewie Griffin의 답변 을 R로 .

JayCe를 인용하려면 :

입력은 첫 번째 열이 시작이고 두 번째 열이 종료 인 행렬입니다. Start <= End를 가정하지만 시작 날짜를 정렬하지 않아도됩니다.

아마도 $c불필요하지만 도전의 정신이 아니기 때문에 포함 시켰습니다.


1
2 바이트에 대한 최소 (x-1)?
JayCe


@JayCe 그래, 좋아! 나는 이것으로 일찍 돌아 가려고했지만 잊었다.
주세페

3

파워 쉘, 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. 의 전화 filter가 더 컴팩트합니다.
mazzy

3

J, 43 바이트

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

입력은 정수 쌍의 목록이며, 각 정수는 임의의 공통 0 일의 오프셋입니다.

언 골프

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

설명

구조는 다음과 같습니다

(A)&:(B) C
  • C는 주 동사를주는 후크를 만듭니다. A&:B 에 왼쪽의 입력과 오른쪽의 평평한 입력
  • B 일명 ((>./ (] + i.@>:@-) <./)"1) 는 목록의 최소값과 최대 값을 가져와 결과 범위를 반환하고 순위 1로 작동하므로 오른쪽의 전체 범위와 왼쪽의 개별 범위를 제공합니다.
  • A는 =순위 "0 _(즉,{ ) 각 입력이 임의의 범위에 나타나는 횟수를 계산합니다. 결국 그것은 매년 그 수치로 가득 차 있습니다.

온라인으로 사용해보십시오!


2

자바 스크립트 (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

온라인으로 사용해보십시오!

undefined0을 의미하고; 첫 번째 요소는 가장 빨리 시작해야합니다

(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

R (70)

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

데이터 프레임을 추정한다 x(두 열로 StartEnd가능하거나 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)...)])

온라인으로 사용해보십시오!

날짜 범위의 배열로 입력을 승인합니다. 배열의 다른 범위 중에서 정렬을 가정하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.