Когда в последний раз дата делилась на n?


24

Дата может быть представлена ​​целым числом без знака как таковое: ГГГГММДД. Что вам нужно сделать, это написать самую короткую программу или функцию, которая вычисляет самую последнюю дату, число которой делилось на данное число n(включая сегодняшнюю дату), а затем возвращает эту дату в формате, показанном выше. Если никогда не было даты (между 00000101 и сегодня включительно), делимой на данное целое число, вы должны вернуть -1.

Примеры

Current Date     Input     Output

30 July, 2014      4       20140728
30 July, 2014      7       20140729
28 July, 2014      4       20140728
28 July, 2014      7       20140722
28 July,    5    90000     -1

вход

Вы можете читать из STDIN или принимать аргумент функции или даже ожидать, что ввод будет сохранен в переменной. На входе будет целое число без знака.

Выход

Записать в STDOUT или вернуть (или сохранить в переменной) целое число, представляющее дату в формате ГГГГММДД.

ограничения

Вы можете использовать любую стандартную библиотеку, которую предлагает ваш язык. Применяются стандартные лазейки .

Условия выигрыша

Это , поэтому выигрывает самая маленькая программа (в байтах). В случае ничьей победит ответ с наибольшим количеством голосов.


4
Дата 00000101 не существует. Отсчет года начинается с 1. en.wikipedia.org/wiki/0_%28year%29
edc65

1
@ edc65 мы можем притвориться, что оно существует?
переигрыватель

3
Как насчет 29 февраля? Нужно ли применять правила полного високосного года, чтобы проверить действительные даты? en.wikipedia.org/wiki/Leap_year
Цифровая травма

6
Что относительно дней, потерянных из-за переключения юлиано-григорианского календаря? Или мы идем по григорианскому пути? en.wikipedia.org/wiki/Gregorian_calendar
Цифровая травма

1
Ваши спецификации ввода / вывода довольно слабые. Например, должно ли «ожидать, что вход будет сохранен в переменной», считать объявление переменной на языке, подобном C? Вы говорите «написать программу», но говорите «принять аргумент функции» - значит ли это, что мы можем написать только функцию, а не полную программу?
Боб

Ответы:


16

Mathematica, 93 60 байт

For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n∣r,];r~Max~-1

Ожидает, что вход будет сохранен в n.

Обратите внимание, что вертикальная линия - это символ Юникода для «деления», который я посчитал как 3 байта (UTF-8).

Редактировать: нашел хитрый трюк, чтобы избежать раздутой DateStringи спецификации формата :).

Изменить: полностью забыл о -1требовании. Исправлено сейчас.

Вот объяснение

For[i=0,            i--                        ,];         (* i is the number of days AFTER
                                                              today. Hence, we decrement 
                                                              it. *)
For[i=0,   DatePlus@i--                        ,];         (* If no reference date is
                                                              provided, DatePlus will add
                                                              the given number of days to
                                                              today's date. The result is a 
                                                              list of 3 integers, luckily 
                                                              in order {year,month,day} *)
For[i=0,   DatePlus@i--~FromDigits~100         ,];         (* Interpret these as the digits
                                                              of a base 100 number. The 
                                                              beauty is that FromDigits
                                                              doesn't care about digits 
                                                              greater than the base and 
                                                              just carries them over. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)        ,];         (* Store the number in r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0      ,];         (* Make sure it's positive. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];         (* And keep going while n does 
                                                              not divide r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];r~Max~-1 (* Clamp result to -1. *)

Обратите внимание, что я использовал |вместо объяснения, потому что Unicode портит моноширинку.


+ 1.У вас есть ссылка, указывающая, что вы должны считать символы в юникоде как 3 байта?
Доктор Велизарий

2
@belisarius В ОП указывалось, что этот код «гольф» исчисляется байтами, а не символами (это также значение по умолчанию, как указано в теге wiki).
Мартин Эндер

Я никогда не читал до конца вики :) Спасибо!
Доктор Велизарий

6

Python 2 - 150

import datetime as d,re
def f(n):
 t=d.date.today()
 while t:
    c=int(re.sub("-","",str(t)))
    if c%n<1:return c
    try:t-=d.timedelta(1)
    except:return-1

Спасибо @ chill0r за предложение удалить days = и Jason S за подсказку, что блок try может быть уменьшен до одной строки.


Да. Это стандартная процедура работы;). После вставки вкладки преобразуются в пробелы.
Векторизовано

Вы можете удалить days=в t-=d.timedelta(days=1). Это тоже отлично работает (по крайней мере, в python3)
chill0r

@bitpwner Ах, я вижу, неважно тогда.
Мартин Эндер

1
Вы можете сохранить больше: (1) использовать int(t.strftime("%Y%m%d"))и отбрасывать re, (2) использовать одну строку, tryпотому что t-=d.timedelta(1)нужно только в нем.
Джейсон С

1
@bitpwner strftimeв более ранние даты работает в python3, проверил, и я получаю ошибку в python2
Jason S

5

C # 136

С пересмотренными спецификациями, функция, которая принимает unsigned int и возвращает int.

int F(uint n){var d=System.DateTime.Now;int i;try{while((i=int.Parse(d.ToString("yyyMMdd")))%n>0)d=d.AddDays(-1);}catch{i=-1;}return i;}

152 символа с переменным вводом / выводом

Используя слабые требования к вводу / выводу, ввод должен быть сохранен в переменной n(в настоящее время считаются все символы, кроме целочисленного литерала), а вывод предоставляется с переменной s.

class P{static void Main(){var n=4;var d=System.DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}}}

204 символа с STDIN / STDOUT:

using System;class P{static void Main(){int n=int.Parse(Console.ReadLine());var d=DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}Console.Write(s);}}

1
Действительно, понижающий голос? Разве это не решает проблему правильно? Пожалуйста, объясни. Если кто-то думает, что я продублировал другой ответ C #, я фактически написал это примерно за час до другого и даже изучил использование C # 6.0 для выражений объявлений. Немного отвлекся, что привело к позднему опубликованию ответа. Даже тогда, это довольно хрупкая причина для снижения.
Боб

4

T-SQL (2012) - 148

Предполагается, что есть свободная переменная @n со значением n.

declare @ date=getdate()while convert(char,@,112)%@n>0 and'00010101'<@ set @=dateadd(d,-1,@)print iif(convert(char,@,112)%@n=0,convert(char,@),'-1')

4

Golflua 90 86

n=I.r()d="%Y%m%d"i=O.d(d)+0j=0@i>0?i%n==0w(i)O.q()$j=j+1i=O.d(d,O.t()-j*86400)+0$w(-1)

Безголосая версия Луа будет,

n = io.read()
d = "%Y%m%d"
i = os.date(d)+0   -- implicitly casts os.date(d) to int
j = 0
while i>0 do
   if i % n == 0 then
      print(i)
      os.exit()
   end
   j = j+1
   i = os.date(d,os.time()-j*86400)+0
end
print(-1)

2
Протестировано здесь n = 20140699 выводов 20140699
Уильям Барбоза

@WilliamBarbosa: исправлено; 20140699 возвращает -1.
Кайл Канос

4

МАТЛАБ: 61

-1,s=str2num(datestr(1:now,'YYYYmmDD')),d=s(~mod(s,n)),d(end)

Предполагается, что делитель хранится в n. Результат будет сохранен в переменной с именем ans.


Комментируемая версия:

-1                                     % Store -1 in ans in case we don't find anything
s=str2num(datestr(1:now,'YYYYmmDD'))   % Make a list of date numbers
d=s(~mod(s,n)),                        % Select only those who are dividable and prepend -1
d(end)                                 % Store last found value in ans, if anything is found

Сгенерирует ошибку, если результат не найден, но ответ по-прежнему доступен в переменной, несмотря на это.


Ошибки можно избежать за счет 2 дополнительных символов:

s=str2num(datestr(1:now,'YYYYmmDD')),d=[-1;s(~mod(s,n))],d(end)

@ MartinBüttner Хмм, решил эту проблему, но теперь решение связано только с минимальными символами. Можете ли вы увидеть какие-либо улучшения?
Деннис Джаэруддин

1
Нет, не с моей головы. Но моя мотивация помочь тебе победить меня немного ограничена. ;)
Мартин Эндер

4

PHP (92 = 85 + 7)

Ожидается, что вход будет сохранен в $n.

for($d=date("Ymd");!($d%$n==0&checkdate($d/100%100,$d%100,substr($d,0,4))|$d<0);$d--);echo$d

Я просто вспомнил, почему я больше не люблю PHP =)

РЕДАКТИРОВАТЬ: Теперь -1 спецификации также реализованы.


Нет, только что проверил, $ d будет слишком низким при отражении. Что ты имеешь в виду под "ты кузница"? (Извините, нет английского языка =)
flawr

О, я не видел эту спецификацию, конечно, это должно быть добавлено, спасибо!
flawr

3

JavaScript (ES6) 115

Ожидается число в переменной n, результат сохраняется в переменной r. Каждый день проверяется, начиная с текущей даты и по убыванию - должен быть лучший способ.
Более того, при использовании стандартных функций дат в JavaScript, все даты являются григорианскими вплоть до 1-го года (соответственно високосные годы неверны до григорианской реформы).

for(z=new Date,t=n+1;t>n&&t%n;)
  d=z.getDate(),
  t=z.getFullYear()*1e4+(z.getMonth()+1)*100+d,
  z.setDate(d-1);
r=t>n?t:-1

3

C # - 144 (или 124 в LINQPad) + 1 для каждой цифры в n

Это предполагает, что вход будет в переменной n. К концу выполнения желаемое значение будет в переменной r. Это считается 00010101первой датой, потому что дата 00000101не существует. Предложения по улучшению всегда приветствуются.

class P{static void Main(){int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}}}

Версия LINQPad:

int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}r.Dump();

3

Groovy - 301 300 символов

Очень простой (и медленный), без хитростей, чтобы скрыть тот факт, что он использует Joda Time.

Golfed:

@Grab(group='joda-time', module='joda-time', version='2.3')
import org.joda.time.*
import org.joda.time.format.*
f={DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int}
n=args[0] as int;b=0;x=-1;c=0
while(!b){if(f(c++)%n==0){x=f(--c);b=1};if(f(0)-c<=101){b=1}}
println x

Пример выполнения (30.07.2014):

$ groovy D.groovy  7
20140729
$ groovy D.groovy  16
20140720
$ groovy D.groovy  90000
-1

Ungolfed:

@Grab(group='joda-time', module='joda-time', version='2.3')

import org.joda.time.*
import org.joda.time.format.*

f = { DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int }

n = args[0] as int
b = 0 
x = -1
c = 0

while (!b) {
    if(f(c++)%n==0) { x=f(--c); b=1}
    if(f(0)-c<=101){b=1}
}

println x

3

R 146 139

D=function(n){
z=as.double(gsub("-","",y<-Sys.Date()))
d=F
while(z>100&!d){
y=y-1 
z=as.double(gsub("-","",y))
d=!z%%n}
ifelse(z>100,z,-1)}

Удачи с датой, которая не работает. microbenchmarkсообщает, что для возврата на 15 дней требуется около полсекунды. По состоянию на 31 июля 2014 г. на то, чтобы выплюнуться, потребуется около 20 миллионов секунд (~ 23 дня) -1, по крайней мере, согласно оборотной стороне конверта.

редактировать : некоторые ярлыки в комментариях


!dкороче чем d==Fи !z%%nчем z%%n==0. Кроме того, превращение as.numeric(gsub("-","",...)в функцию должно также уменьшить количество символов. Тем не менее, хорошая работа!
plannapus

Ох, и as.realчасто это хорошая, более короткая альтернатива as.numeric.
plannapus

К сожалению, as.realне существует R 3.0.0. Но у нас все еще есть, as.doubleкоторый на один символ короче.
теневик

О, я не знал этого, поскольку я все еще использую R 2.14
plannapus

1
Я не работаю на компьютере, на котором у меня есть права администратора, так что это не мое дело. Но у меня уже paste0по моему .Rprofileестественно :)
plannapus

3

Matlab 104

function d=f(v);for d=fix(now):-1:1 d=str2num(datestr(d,'YYYYmmDD'));if~mod(d,v)return;end;end;d=-1;end

Ungolfed:

function d = f(v)
   for d=fix(now):-1:1
       d = str2num(datestr(d,'YYYYmmDD'));
       if ~mod(d,v)
          return; 
       end
   end
   d = -1;
end

РЕДАКТИРОВАТЬ: мне удалось немного оптимизировать его, но @DennisJaheruddin имеет реальное решение здесь


Это все еще может быть игра в гольф совсем немного, я буду обновлять это.
Деннис Джаэруддин

@DennisJaheruddin Я отклонил ваши изменения на основе этого мета-поста . Пожалуйста, предложите свои улучшения в комментарии, чтобы ОП мог просмотреть их, прежде чем изменять свой ответ.
Мартин Эндер

Обратите внимание, что вы можете сохранять символы различными способами: используйте скрипт, а не функцию, пусть вещи назначаются на ans, выполняйте цикл от низкого до высокого и каждый результат перезаписывает предыдущий, так что вам не нужно прерывать цикл. , - Конечно, векторизация также может помочь, см. Мой ответ .
Деннис Джаэруддин

Вот более короткая петлевая версия из 67 символов:-1,for s=str2num(datestr(1:now,'YYYYmmDD'))',if~mod(s,n),+s,end,end
Деннис Джаэруддин

@ MartinBüttner Спасибо за комментарий. Как вы сказали, произошла ошибка. Теперь все должно быть в порядке.
Скотт

3

Python 3 - 151 148 байт, генераторы

from datetime import*
t=date.today()
f=lambda n:next((y for y in(int((t-timedelta(o)).strftime("%Y%m%d"))for o in range(t.toordinal()))if y%n<1),-1)

Спасибо @ nyuszika7h за import*предложение


2

Ruby 103

require'date'
f=->{d=Date.today 
(s=d.strftime('%Y%m%d').to_i
return s if s%n<1
d-=1)while d.year>0
-1}

вход

Ожидает, что значение делителя будет присутствовать в переменной n.

Выход

Возвращаемое значение fфункции

Пример в сети: http://ideone.com/LoYxG4


2

Ява: 373 символа

Это порт ответа Groovy, который использует Joda Time.

Golfed:

import org.joda.time.*;
import org.joda.time.format.*;
public class D {
static int f(int i){return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));}
public static void main(String[] args){
int n=Integer.parseInt(args[0]);int b=0,c=0,x=-1;
while(b!=1){if(f(c++)%n==0){x=f(--c);b=1;};if(f(0)-c<=101){b=1;}}
System.out.println(x);}}

Примеры прогонов (с joda-time-2.4.jar на пути к классам:

$ java D 7
20140729
$ java D 4
20140728
$ java D 16
20140720
$ java D 90000
-1

Ungolfed:

import org.joda.time.*;
import org.joda.time.format.*;

public class D {
    static int f(int i) {
        return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));
    }

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        int b = 0,c = 0,x = -1;

        while(b!=1) {
            if(f(c++)%n==0) { x=f(--c);b=1; }
            if(f(0)-c<=101) { b=1; }
        }

        System.out.println(x);
    }
}

3
Там же java.time.*в последней версии Java.
ntoskrnl

2

Bash + coreutils (8.21), 67 байт

seq -f-%gday $[9**9]|date -f- +[pq]sp[_1pq]sq%Y%m%ddA1=qd$1%%0=p|dc
  • seqгенерирует целые числа от 1 до 9 9 , по одному на строку, и форматирует его как-<x>day
  • это канал, по date -fкоторому интерпретируется каждая строка и выводится дата, отформатированная в dcвыражение, например [pq] sp [_1pq] sq 20140728 d A1 =q d 7% 0=p(пробелы добавлены для удобства чтения)
    • [pq] определить макрос для печати вершины стека, затем выйти
    • sp сохранить макрос в регистре p
    • [pq] определите макрос для нажатия -1, напечатайте верхнюю часть стека, затем выйдите
    • sq сохранить макрос в регистре q
    • 20140728 целое число встроенной даты
    • d дубликат вершины стека
    • A1 нажать 101 (00000101)
    • =q2 верхних значения стека: сравните дату и 101 и вызовите макрос, qесли он равен
    • 7 толкатель
    • % поп делитель и делитель, разделяй и толкай остаток
    • 0 нажать 0
    • =p2 верхних значения стека: сравните остаток и 0 и вызовите макрос, pесли он равен
    • d дубликат вершины стека
    • макрос pназывается: печатает целое число даты и dcполностью выходит
  • dcвыражения передаются dcдля оценки. Как только dcпечатает правильное значение и выходит, остальная часть конвейера срывается

Выход:

$ ./lastdivdate.sh 4
20140728
$ ./lastdivdate.sh 7
20140729
$ ./lastdivdate.sh 123456
17901120
$ ./lastdivdate.sh 77777
19910912
$ ./lastdivdate.sh 7777777
-1
$ 

Поскольку эта программа генерирует целые числа от 1 до 9 9 , она будет действительна в течение чуть более 1 миллиона лет в будущем. Я надеюсь, что это ограничение приемлемо ;-)


Спасибо @ WumpusQ.Wumbley за сокращение возврата -1.


@ MartinBüttner Проклятия! Теперь так и есть, с 19-байтовым штрафом :)
Digital Trauma

Более короткие способы преобразования пустого вывода в -1: добавьте |grep .||echo -1в конец конвейера или используйте zsh, где вы можете вкладывать расширения, например echo ${$(cmd):-1}(это будет стоить вам обратной косой черты в другом месте ...)

@ WumpusQ.Wumbley Почему я не подумал об этом? Благодарность!
Цифровая травма

1
Кстати, это, кажется, чувствительно к версии coreutils. Шахта (8.15) отказывается возвращаться до 1901 года со спецификацией «дней назад».

1
На самом деле это кажется sizeof time_tпроблемой, поскольку граница, на которой она прорывается, составляет 2 ** 31 секунду до 1 января 1970 года. Моя старая установка тоже патетически 32-битная

2

Питон: 134 байта

Не удастся победить нынешнего лидера, и это не намного лучше, чем лучший ответ Python, но я решил опубликовать свое лучшее решение Python.

from datetime import*
def y(a,n):
 s=a.strftime("%Y%m%d")
 if int(s)%n==0:yield s
 try:x=y(a-timedelta(1),n)
 except:yield -1
 yield x

Ungolfed:

from datetime import *
def y(a, n):
    s=int(a.strftime("%Y%m%d"))
    if s%n==0:
        yield s
    try:
        x=y(a-timedelta(1), n)
    except:
        yield -1
    yield x

На самом деле это 138 байтов. Вы можете сохранить 4 байта, используя from datetime import*вместо import datetime as d, timedelta(1)вместо d.timedelta(1)и yieldвместо return.
nyuszika7h

Я использую случайный онлайн счетчик байтов, есть ли лучший вариант?
RageCage


Что отличает этот от этого? bytecount.bluebus112.com
RageCage

Тот не учитывает переводы строки, плюс он учитывает символы , а не байты. Для текста ASCII два одинаковы, поэтому последний здесь не имеет значения. В код-гольфе вы обычно учитываете символы, если ОП не говорит иначе. (Кроме того, тот, который я связал, был первым результатом в Google для "количества байтов" здесь.)
nyuszika7h

2

JavaScript (ES5) - 94

Он ожидает ввод в переменной xи помещает вывод в o.

for(i=Date.now();i>-7e13&&(o=(new Date(i)).toISOString().replace(/-|T.*/g,''))%x;i-=864e5)o=-1

2

к4 (84) (73)

f:{f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;.z.D];x]}

Это просто начальная версия с первым алгоритмом, который пришел в голову; Я уверен, что лучшее возможно как по производительности, так и по длине.

Эта версия жестко кодирует часть «сегодня» (это .z.D); измените его на date literal ( yyyy.mm.dd) или на целое число в системе q date (количество дней с 1 января 2000 года) для запуска тестовых случаев. (q не будет анализировать литералы даты раньше, чем в начале восемнадцатого века, поэтому для дат до этого вам нужно будет определить значение и напрямую использовать соответствующее целое число. 1 января "AD 0" из спецификации поворачивается out to be -730457, который используется в коде функции. 28 июля AD 5 из последнего контрольного примера оказывается -728450.)

Данные тестовые случаи:

  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}7
20140729
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}7
20140722
  "d"$-728450
0005.07.28
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;-728450];x]}90000
-1

редактировать:

g:.,/$`\:`$$:;f:{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}

Это другой подход, который использует один из операторов сходимости для уменьшения даты до тех пор, пока она не найдет делимую или не пересечет границу 1/1/0000. Это также делает преобразование из даты в целое число немного по-другому.

Тестовые случаи, на этот раз все сразу:

  g:.,/$`\:`$$:;{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}'[2014.07.30 2014.07.30 2014.07.28 2014.07.28,"d"$-728450;4 7 4 7 90000]
20140728 20140729 20140728 20140722 -1

1

VBA 343 байта (модуль)

Sub divD(i As Long)
a = Now()
b = Format(a, "yyyymmdd")
    Do While b / i <> Int(b / i)
    a = DateAdd("d", -1, a)
    b = Format(a, "yyyymmdd")
        If b = "01000101" Then
            MsgBox -1
            Exit Sub
        End If
    Loop
MsgBox b
End Sub

Это может быть сильно сжато до Sub d(i):a=Now:b=a:Do Until b/i=Int(b/i):a=DateAdd("d",-1,a):b=Format(a,"yyyymmdd"):If b="01000101"Then:b=-1:Exit Sub:Loop:Debug.?b:End Sub139 байт
Тейлор Скотт

1

PowerShell - 76

Это зависит от числа, хранящегося в переменной $n.

try{@(0..$n|%{'{0:yyyyMMdd}'-f(date).AddDays(-$_)}|?{!($_%$n)})[0]}catch{-1}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.