Подсчитайте время

17

Вдохновленный реальным сценарием, на который я попросил ответить здесь: /superuser/1312212/writing-a-formula-to-count-how-many-times-each-date- появляется в-а-набор просрочен-RAN

Учитывая массив временных интервалов (или пар startdate-enddate), выведите количество временных интервалов, охватывающих каждый день, для всех дней в общем диапазоне.

Например:

  #      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

Входными данными могут быть любые форматы, представляющие набор временных интервалов, например, набор пар времени или набор (встроенных) объектов, содержащих даты начала и окончания. Дата-время ограничено между 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

Другие алгоритмы, чтобы получить тот же результат в порядке.

simonalexander2005
источник
3
Требуется ли массив целых чисел или нам разрешено возвращать что-то еще, например, словарь с ключами в качестве каждой даты? Если нам разрешено возвращать словарь, то можем ли мы опустить даты, которых нет ни в одном из временных интервалов?
JungHwan Мин
1
Можем ли мы принять ввод как два списка, один с датами начала и другой с соответствующими датами окончания?
Джузеппе
Да, все это хорошо, кроме пропуска даты - я прямо говорю, что в этом случае должен быть
выведен 0
3
Могу я спросить, почему 0должен быть в словаре? Это только вынуждает пользователя переходить от min(input)к max(input), что, кажется, не добавляет ничего к ядру задачи (вычисление временных интервалов).
JungHwan Мин
2
@JungHwanMin Я думаю, это не меняет его; но поскольку я явно указал это в спецификации, когда я его опубликовал, я не хочу возиться с ним и заставлять кого-то еще
повторять

Ответы:

3

APL (Dyalog Unicode) , 32 байта SBCS

Полная программа. Запрашивает в stdin список пар международных номеров дат (например, какие используются Excel и MATLAB). И список, и пары могут быть заданы в любом порядке, например (Конец, Старт). Выводит список значений в стандартный вывод.

¯1+⊢∘≢⌸(R,⊢)∊(R←⌊/,⌊/+∘⍳⌈/-⌊/)¨⎕Попробуйте онлайн!

Если это неверно, список (YMD) пар может быть преобразован для дополнительных 21 байта, всего 53:

¯1+⊢∘≢⌸(R,⊢)∊(R⌊/,⌊/+∘⍳⌈/-⌊/)¨{2⎕NQ#'DateToIDN'⍵}¨¨⎕Попробуйте онлайн!


 подскажите консоль для оцененного ввода

( Применить следующую молчаливую функцию к каждой паре

⌊/ минимальное (лит. мин-сокращение), т.е. дата начала

⌈/- максимальная (т.е. дата окончания) минус

⌊/+∘⍳ дата начала плюс диапазон от 1 до что

⌊/, дата начала, предшествующая этому

R← назначить эту функцию R(для R ange)

ε NLIST (Flatten) перечень диапазонов в один список

() Примените к этому следующую молчаливую функцию:

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)

Arnauld
источник
Ах, орехи!
Лохматый
Сохраните байт, взяв примитивные значения в качестве входных данных: 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 ), в основном порядок вставки для строковых и символьных ключей (и Nodejs TIO, похоже, так и выглядит: 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],"<="))

Попробуйте онлайн!

Ввод - это матрица, первый столбец которой - начало, а второй - конец. Предполагается начало <= конец, но не требует сортировки дат начала.

Jayce
источник
Это насколько я смог попытаться повторить октавский ответ Стьюи Гриффин ... что я делаю не так?
JayCe
это из-за способа, которым R делает свои мусорные ведра в hist; вы могли бы сделать , c(-25668,min(x):max(x))так как -25568это , прежде , 1900но это заканчивается быть больше , чем ваш предложенный ответ. Тем не менее, есть лучший способ создать даты, чем apply; У меня есть один, который на 68 байтов, и я просто не нашел время, чтобы опубликовать его сам.
Джузеппе
Ах, нет, на самом деле, используйте, (min(x)-1):max(x)и это должно работать, как ожидалось; тогда, если вы можете найти applyспособ генерирования дат, вы можете получить это до 63 байтов и связать ответ Octave.
Джузеппе
@Giuseppe Вы должны опубликовать это как отдельный ответ :)
JayCe
отправил :-) Я должен признать, что я использовал tableи factorдо этого, который был моим первоначальным использованием 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 байт благодаря Джонатану Аллану
+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.
Джонатан Аллан
... на самом деле я думаю, что вы можете отбросить from datetime import*и заменить d+=timedelta(days=1)на, d+=type(d-d)(1)так как входы уже dates. 87 байтов
Джонатан Аллан
1
Кажется, это предполагает, что начало первого диапазона является самой низкой датой, а конец последнего диапазона является самым высоким - но я думаю, что это иногда невозможно, даже если ОП позволяет нам принимать отсортированные данные. Например, если вход есть [(2001-01-01, 2001-01-05), (2001-01-02, 2001-01-03)]. Если OP не позволяет нам разделять и переупорядочивать эти диапазоны во время предварительной обработки (что кажется маловероятным), этот ввод не может быть обработан этим кодом должным образом.
sundar - Восстановить Монику
@sundar Да, я понимаю, о чем ты говоришь. Я обновил решение, чтобы справиться с этим. Благодарность!
Мертвый опоссум
3

Wolfram Language (Mathematica) , 62 байта

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

Попробуйте онлайн!

+35 байт, потому что OP указал, что 0должно быть включено в вывод.

Если пропустить запись в словаре были разрешены, 27 байтов

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

Попробуйте онлайн!

Встроенный DayRangeпринимает два DateObjects (или строковый эквивалент) и выводит список Datesмежду этими датами (включительно).

Юнг Хван Мин
источник
3

R , 65 63 байта

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

Попробуйте онлайн!

Это сотрудничество между JayCe и мной, переносом ответа Стью Гриффин на R.

Цитировать JayCe:

Ввод - это матрица, первый столбец которой - начало, а второй - конец. Предполагается начало <= конец, но не требует сортировки дат начала.

Возможно, $cэто не нужно, но это не совсем в духе задачи, поэтому я включил его.

Giuseppe
источник
1
Мин (х-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)
Mazzy
источник
Благодарность! $cnt.Keys.Dateконечно.
Маззи
-3 байта: functionзаменено на scriptblock. коды для игры в гольф и без игры проверяются.
Маззи
-5 байт: scriptblockзаменено на filter. Зов filterболее компактен.
Маззи
3

J, 43 байта

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

входные данные представляют собой список пар целых чисел, где каждое целое число является смещением от любого произвольного общего 0-дневного дня.

ungolfed

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

объяснение

структура это:

(A)&:(B) C
  • C создает крюк, который дает основной глагол A&:B вход слева, а вход сплющенный справа
  • B aka ((>./ (] + i.@>:@-) <./)"1)берет минимальное и максимальное значения из списка, возвращает результирующий диапазон и действует с рангом 1. следовательно, он дает общий диапазон справа и отдельные диапазоны слева.
  • Затем A использует значение =rank "0 _(т. Е. Rank of {), чтобы подсчитать, сколько раз каждый вход появляется в любом из диапазонов. наконец-то это происходит каждый год по этим показателям.

Попробуйте онлайн!

Ион
источник
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 короче, если вы видите только элементы и используете больше стека

l4m2
источник
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возможно, Sи E) с датами (класс Date).

Попробуйте онлайн

lebatsnok
источник
Привет, не могли бы вы включить ссылки 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...)]

Попробуйте онлайн!

Вдохновленный решением Python @ DeadPossum .

Принимает входные данные в виде матрицы, в которой каждая строка имеет две даты: начальную и конечную даты диапазона ввода. Предполагается, что входные данные имеют самую раннюю дату в первую очередь, и что каждая строка имеет первую дату начала, но не предполагает никакой сортировки за пределами сортировки между различными строками.


Старое решение:

Юлия 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)...)])

Попробуйте онлайн!

Принимает ввод как массив диапазонов дат. Не предполагает никакой сортировки между различными диапазонами в массиве.

sundar - Восстановить Монику
источник