Quantos anos tem aproximadamente?

29

Escreva um programa curto, que leva um número positivo de segundos representando uma idade e gera uma estimativa desse tempo em inglês.

Seu programa deve gerar a quantidade menos precisa de tempo decorrida, entre as seguintes métricas e seus comprimentos em segundos:

second = 1
minute = 60
hour   = 60 * 60
day    = 60 * 60 * 24
week   = 60 * 60 * 24 * 7
month  = 60 * 60 * 24 * 31
year   = 60 * 60 * 24 * 365

Exemplos

input      : output
1          : 1 second
59         : 59 seconds
60         : 1 minute
119        : 1 minute
120        : 2 minutes
43200      : 12 hours
86401      : 1 day
1815603    : 3 weeks
1426636800 : 45 years

Como você pode ver acima, após o tempo, digamos, 1 dia (60 * 60 * 24 = 86400 segundos), não produzimos mais minutos ou horas , mas apenas alguns dias até ultrapassar o tempo de uma semana , e assim por diante.

Considere o período de tempo especificado como uma idade. Por exemplo, após 119 segundos, 1 minuto se passou , não 2.

Regras

  • Nenhuma especificação para 0 ou entradas negativas.
  • Siga a pluralização adequada. Toda medida maior que 1 deve incluir uma ssequência da palavra.
  • Você não pode usar uma biblioteca pré-existente que atenda à função de todo o programa.
  • Este é um código de golfe, o programa mais curto ganha os pontos de internet.
  • Diverta-se!
um pouco confuso
fonte
3
Não entendo como escolhemos uma unidade ou quantia. Nós arredondamos?
Xnor
11
@xnor dividimos por inteiro e usamos o menor valor diferente de zero junto com sua unidade (possivelmente pluralizada). Portanto, 59 -> "59 segundos" e 86401 -> "1 dia".
Jonathan Allan
5
Bem-vindo ao PPCG! Bom primeiro desafio. Para referência futura, existe uma caixa de proteção que é útil para obter feedback antes de postar no main.
Jonathan Allan
4
Observe que Fazer X sem Y é desencorajado, assim como requisitos de programa não observáveis .
user202729
11
Como devemos arredondar os números? 119 segundos devem durar 1 minuto ou 2 minutos? E quanto a 90?
user202729

Respostas:

8

Geléia , 62 bytes

TṀị
“¢<<ð¢‘×\×€0¦7,31,365F⁸:µç“ɲþḣ⁹ḢṡṾDU¤µQƝṁ⁼ẹ»Ḳ¤ṭÇK;⁸Ç>1¤¡”s

Um programa completo imprimindo o resultado.
(Como um link monádico, ele retorna uma lista de um número inteiro seguido por caracteres)

Experimente online!

Quão?

TṀị - Link 1: list of integers, K; list, V  e.g. [86401,1440,24,1,0,0,0], ["second","minute","hour","day","week","month","year"]
T   - truthy indexes of K                        [1,2,3,4]
 Ṁ  - maximum                                    4
  ị - index into V                               "day"

“¢<<ð¢‘×\×€0¦7,31,365F⁸:µç“...»Ḳ¤ṭÇK;⁸Ç>1¤¡”s - Main link: integer, N  e.g. 3599
“¢<<𢑠                                      - list of code-page indices = [1,60,60,24,1]
        \                                     - cumulative reduce with:
       ×                                      -  multiplication = [1,60,3600,86400,86400]
             7,31,365                         - list of integers = [7,31,365]
            ¦                                 - sparse application...
           0                                  - ...to index: 0 (rightmost)
         ×€                                   - ...of: multiplication for €ach = [1,60,3600,86400,[604800,2678400,31536000]]
                     F                        - flatten = [1,60,3600,86400,604800,2678400,31536000]
                      ⁸                       - chain's left argument, N    3599
                       :                      - integer divide         [3599,59,0,0,0,0,0]
                        µ                     - start a new monadic chain, call that X
                                ¤             - nilad followed by links as a nilad:
                          “...»               -   compression of "second minute hour day week month year"
                               Ḳ              -   split at spaces = ["second","minute","hour","day","week","month","year"]
                         ç                    - call the last link (1) as a dyad - i.e. f(X,["second","minute","hour","day","week","month","year"])
                                              -                             "minute"
                                  Ç           - call the last link (1) as a monad - i.e. f(X,X)
                                              -                             59
                                 ṭ            - tack                        [59,['m','i','n','u','t','e']]
                                   K          - join with spaces            [59,' ','m','i','n','u','t','e']
                                           ”s - literal character '
                                          ¡   - repeat...
                                         ¤    - ...number of times: nilad followed by link(s) as a nilad:
                                     ⁸        -   chain's left argument, X  [3599,59,0,0,0,0,0]
                                      Ç       -   call the last link (1) as a monad - i.e. f(X,X)
                                              -                             59
                                       >1     -   greater than 1?           1
                                    ;         - concatenate                 [59,' ','m','i','n','u','t','e','s']
                                              - implicit print - smashes to print  "59 minutes"
Jonathan Allan
fonte
8

C, 194 180 144 128 caracteres

Obrigado a @gastropher pelas reduções de código. Esqueci que C permite parâmetros implícitos usando funções no estilo K & R! Agradeço também ao @gmatht pela idéia de colocar literais dentro, em vez de matrizes. Eu estendi isso aos personagens abusando, tirando proveito de caracteres / char16_tstrings amplos ! O compilador não parece gostar \1da sua forma though.

f(t,c,d){for(c=7;!(d=t/L"\1<ฐ\1•▼ŭ"[--c]/(c>2?86400:1)););printf("%d %.6s%s\n",d,c*6+(char*)u"敳潣摮業畮整潨牵 慤y†敷步 潭瑮h敹牡",(d<2)+"s");}

Experimente online!

Solução original

Dividi as matrizes em linhas separadas para facilitar a visualização do restante da solução.

char *n[]={"second","minute","hour","day","week","month","year"};
int o[]={1,60,3600,86400,604800,2678400,31536000};
f(int t){int c=7,d;while(!(d=t/o[--c]));printf("%d %s%s\n",d,n[c],d>1?"s":"");}

Experimente online!

Executando os divisores na ordem do maior para o menor, obtemos a unidade de tempo mais grossa. O programa se comporta mal se você der 0 segundos, mas como a especificação exclui explicitamente esse valor, considero aceitável.

ErikF
fonte
Alguns truques podem ser usados ​​para reduzi-lo a 183 bytes: Experimente online!
Gastropner 18/0318
11
Desculpe, esse introduziu um bug. Apropriado em 180 bytes: Experimente online!
Gastropner 18/0318
@gastropner Acho que o último também tem um bug. '(d <1)' deve ser '(d <2)' ... ou '(d <= 1)', mas não vamos enlouquecer.
gmatht
@gmatht Você está certo!
Gastropner 18/0318
OK, último, eu prometo. 164 bytes.
Gastropner 18/0318
7

Perl 5 , 110 bytes

year31536000month2678400week604800day86400hour3600minute60second1=~s:\D+:say"$% $&",$_=$%>1&&"s"if$%=$_/$':reg

Experimente online!

Ton Hospel
fonte
5

Stax , 54 bytes

▀♂♂┼╕Qá◙à*ä∙Φò►⌠╨Ns↔║►πîÇ∙cI≡ªb?δ♪9gΓ╕┬≥‼⌡Öå01:♪EoE╘≡ë

Execute e depure

Aqui está a representação ASCII descompactada e não empacotada do mesmo programa.

                            stack starts with total seconds
c60/                        push total minutes to stack
c60/                        ... hours 
c24/                        ... days
Yc7/                        ... weeks
y31/                        ... months
y365/                       ... years
L                           make a list out of all the calculated time units
`)sQP(dr'pk,oV4?_HIFD?x`j   compressed literal for singular forms of unit names
\                           zip totals with names
rF                          foreach pair of total and name (in reverse orer)
  h!C                       skip if the current total is falsey (0)
  _J                        join the total and unit name with a space
  's_1=T+                   concat 's' unless the total is one

Após a execução, como não há outra saída, a parte superior da pilha é impressa implicitamente.

Execute este

recursivo
fonte
5

JavaScript (ES6), 131 bytes

n=>[60,60,24,7,31/7,365/31,0].map((v,i)=>s=n<1?s:(k=n|0)+' '+'second,minute,hour,day,week,month,year'.split`,`[n/=v,i])|k>1?s+'s':s

Experimente online!

Arnauld
fonte
Eu não estava ciente da sintaxe que você usou (dividir ,). Eu aprendi algo novo. Ótima solução.
18718 Makotosan
11
@ Makotosan Observe que o que realmente é passado splité a matriz [',']. Portanto, isso funciona apenas com funções que forçam coerção a uma string.
Arnauld
3

Java 8, 197 195 157 bytes

n->(n<60?n+" second":(n/=60)<60?n+" minute":(n/=60)<24?n+" hour":(n/=24)<7?n+" day":n<31?(n/=7)+" week":n<365?(n/=31)+" month":(n/=365)+" year")+(n>1?"s":"")

-38 bytes graças a @ OlivierGrégoire .

Explicação:

Experimente online.

n->               // Method with long parameter and String return-type
  (n<60?          //  If `n` is below 60:
    n             //   Output `n`
    +" second"    //   + " second"
   :(n/=60)<60?   //  Else-if `n` is below 60*60
    n             //   Integer-divide `n` by 60, and output it
    +" minute"    //   + " minute"
   :(n/=60)<24?   //  Else-if `n` is below 60*60*24:
    n             //   Integer-divide `n` by 60*60, and output it
    +" hour"      //   + " hour"
   :(n/=24)<7?    //  Else-if `n` is below 60*60*24*7:
    n             //   Integer-divide `n` by 60*60*24, and output it
    +" day"       //   + " day"
   :n<31?         //  Else-if `n` is below 60*60*24*31:
    (n/=7)        //   Integer-divide `n` by 60*60*24*7, and output it
    +" week"      //   + " week"
   :n<365?        //  Else-if `n` is below 60*60*24*365:
    (n/=31)       //   Integer-divide `n` by 60*60*24*31, and output it
    +" month"     //   + " month"
   :              //  Else:
    (n/=365)      //   Integer-divide `n` by 60*60*24*365, and output it
    +" year")     //   + " year"
   +(n>1?"s":"")  //  And add a trailing (plural) "s" if (the new) `n` is larger than 1
Kevin Cruijssen
fonte
11
157 bytes . Acabei de jogar seus números para números mais curtos e me mudei /=para onde necessário.
Olivier Grégoire
Favorito pessoal: n->{for(int t=60,d[]={1,t,t*=60,t*=24,t*7,t*31,t*365},x=7;;)if(n>=d[--x])return(n/=d[x])+" "+"second,minute,hour,day,week,month,year".split(",")[x]+(n>1?"s":"");}(162 bytes), provavelmente uma boa base para jogar golfe.
Olivier Grégoire
Salvar 9 bytes utilizando n/7+, em vez de (n/=7)+etc.
Neil
@ Neil Receio que isso não funcione. Por exemplo, se a entrada for 2678400, a saída deve ser em 1 monthvez de 1 months(singular em vez de plural).
Kevin Cruijssen 22/03
Oh, sutil, obrigado por me informar.
Neil
2

KOTLIN , 205 203 196 bytes

x->val d=86400
with(listOf(1 to "second",60 to "minute",3600 to "hour",d to "day",d*7 to "week",d*31 to "month",d*365 to "year").last{x>=it.first}){val c=x/first
"$c ${second+if(c>1)"s" else ""}"}

Experimente online!

Makotosan
fonte
2

T-SQL , 306 bytes (281 bytes sem E / S)

DECLARE @n INT=1
DECLARE @r VARCHAR(30)=TRIM(COALESCE(STR(NULLIF(@n/31536000,0))+' year',STR(NULLIF(@n/2678400,0))+' month',STR(NULLIF(@n/604800,0))+' week',STR(NULLIF(@n/86400,0))+' day',STR(NULLIF(@n/3600,0))+' hour',STR(NULLIF(@n/60,0))+' minute',STR(@n)+' second'))IF LEFT(@r,2)>1 SET @r+='s'
PRINT @r
Razvan Socol
fonte
Dois pequenos erros de digitação: TRIMnão está definido, isso possivelmente deveria ser LTRIM. Entre weeke day, você tem um + , deve ser um,
Stephan Bauer
De fato, em vez disso + , deveria ser um ,e eu o corrigi agora. No entanto, a TRIMfunção está definida desde o SQL Server 2017. Obrigado.
Razvan Socol
2

R , 157 bytes

function(n,x=cumprod(c(1,60,60,24,7,31/7,365/31)),i=cut(n,x),o=n%/%x[i])cat(o," ",c("second","minute","hour","day","week","year")[i],"if"(o>1,"s",""),sep="")

Experimente online!

cuté útil, pois divide os intervalos em factors, que são armazenados internamente como integers, o que significa que também podemos usá-los como índices de array. Provavelmente, podemos fazer algo um pouco mais inteligente com os nomes dos períodos, mas ainda não consigo descobrir.

Giuseppe
fonte
2

APL + WIN, 88 119 bytes

A versão original perdeu semanas e meses, como apontado por Phil H; (

Solicita a entrada na tela do número de segundos

a←⌽<\⌽1≤b←⎕÷×\1 60 60 24 7,(31÷7),365÷31⋄b,(-(b←⌊a/b)=1)↓∊a/'seconds' 'minutes' 'hours' 'days' 'weeks' 'months' 'years'

Explicação

b←⎕÷×\1 60 60 24 7,(31÷7),365÷31 prompts for input and converts to years, days, hours, minutes, seconds

a←⌽<\⌽1≤b identify largest unit of time and assign it to a

a/'years' 'days' 'hours' 'minutes' 'seconds' select time unit

(-(b←⌊a/b)=1)↓∊ determine if singular if so drop final s in time unit

b, concatenate number of units to time unit from previous steps
Graham
fonte
Alguém comeu semanas e meses?
Phil H
@PhilH Cookie monster? ;) Obrigado. Resposta editada em conformidade.
Graham
Parecia muito elegante, mesmo para APL! Além disso, como você está contando os bytes? Conto 119 caracteres em vez de bytes ...
Phil H
@PhilH Eu não entendo o seu comentário primeiro concordamos em 119 bytes que eu mudei na edição da resposta e, acima de você não diz quantos bytes você está questionando
Graham
1

JavaScript (Node.js) , 177 bytes

x=>{return d=86400,v=[[d*365,'year'],[d*31,'month'],[d*7,'week'],[d,'day'],[3600,'hour'],[60,'minute'],[1,'second']].find(i=>x>=i[0]),c=parseInt(x/v[0]),c+' '+v[1]+(c>1?'s':'')}

Experimente online!

Makotosan
fonte
1

Lote, 185 bytes

@for %%t in (1.second 60.minute 3600.hour 43200.day 302400.week, 1339200.month, 15768000.year)do @if %1 geq %%~nt set/an=%1/%%~nt&set u=%%~xt
@if %n% gtr 1 set u=%u%s
@echo %n%%u:.= %
Neil
fonte
1

Python 2 , 146 144 bytes

lambda n,d=86400:[`n/x`+' '+y+'s'*(n/x>1)for x,y in zip([365*d,31*d,7*d,d,3600,60,1],'year month week day hour minute second'.split())if n/x][0]

Experimente online!

2 bytes salvos graças a Jonathan Allan

Chas Brown
fonte
11
if n/xsalva um byte.
Jonathan Allan
11
Inverter a ordem e indexar com 0salva outra.
Jonathan Allan
1

PHP , 183 bytes

<?$a=[second=>$l=1,minute=>60,hour=>60,day=>24,week=>7,month=>31/7,year=>365/31];foreach($a as$p=>$n){$q=$n*$l;if($q<=$s=$argv[1])$r=($m=floor($s/$q))." $p".($m>1?s:"");$l=$q;}echo$r;

Experimente online!

Jo.
fonte
1

Julia 0.6 , 161 bytes

f(n,d=cumprod([1,60,60,24,7,31/7,365/31]),r=div.(n,d),i=findlast(r.>=1),l=Int(r[i]))="$l $(split("second minute hour day week month year",' ')[i])$("s"^(l>1*1))"

Experimente online!

niczky12
fonte
0

Ruby , 129 bytes

->n{x=[365*d=24*k=3600,d*31,d*7,d,k,60,1].index{|j|0<d=n/k=j};"#{d} #{%w{year month week day hour minute second}[x]}#{d>1??s:p}"}

Experimente online!

Asone Tuhid
fonte
0

Perl 6 / Rakudo 138 bytes

Tenho certeza de que há mais a seguir, mas por enquanto

{my @d=(365/31,31/7,7,24,60,60);$_/[email protected] while @d&&$_>@d[*-1];$_.Int~" "~ <year month week day hour minute second>[+@d]~($_>1??"s"!!"")}

Explicar:

{ # bare code block, implicit $_ input
    my @d=(365/31,31/7,7,24,60,60); # ratios between units
    $_ /= @d.pop while @d && $_ > @d[*-1]; # pop ratios off @d until dwarfed
    $_.Int~   # implicitly output: rounded count
        " "~  # space
        <year month week day hour minute second>[+@d]~ # unit given @d
        ($_>1??"s"!!"")  # plural
}
Phil H
fonte
0

R, 336

Trabalho em progresso

function(x){
a=cumprod(c(1,60,60,24,7,31/7,365/31))
t=c("second","minute","hour","day","week","month")
e=as.data.frame(cbind(table(cut(x,a,t)),a,t))
y=x%/%as.integer(as.character(e$a[e$V1==1]))
ifelse(x>=a[7],paste(x%/%a[7],ifelse(x%/%a[7]==1,"year","years")),
ifelse(y>1,paste(y,paste0(e$t[e$V1==1],"s")),paste(y,e$t[e$V1==1])))}
Riccardo Camon
fonte
0

R , 246 bytes

f=function(x,r=as.integer(strsplit(strftime(as.POSIXlt(x,"","1970-01-01"),"%Y %m %V %d %H %M %S")," ")[[1]])-c(1970,1,1,1,1,0,0),i=which.max(r>0)){cat(r[i],paste0(c("year","month","week","day","hour","minute","second")[i],ifelse(r[i]>1,"s","")))}

Experimente online!

Isso é usar formatação de tempo em vez de aritmética, apenas para o inferno. Talvez outros possam tornar isso menor?

niczky12
fonte