Ile lat ma w przybliżeniu?

29

Napisz krótki program, który zajmuje dodatnią liczbę sekund reprezentujących wiek i wyświetla przybliżony czas w języku angielskim.

Twój program musi wydać najmniej dokładny czas, który upłynął, spośród następujących wskaźników i ich długości w sekundach:

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

Przykłady

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

Jak widać powyżej, po upływie powiedzmy 1 dnia (60 * 60 * 24 = 86400 sekund), nie podajemy już minut (y) ani godzin (y) , a jedynie dni do przekroczenia czasu jednego tygodnia , i tak dalej.

Rozważ podany czas jako wiek. Na przykład po 119 sekundach minęła 1 minuta , a nie 2.

Zasady

  • Brak specyfikacji dla 0 lub ujemnych danych wejściowych.
  • Postępuj zgodnie z właściwą liczbą mnogą. Każdy takt większy niż 1 musi zawierać snastępujący wyraz.
  • Nie możesz używać wcześniej istniejącej biblioteki, która pełni funkcję całego programu.
  • To jest golf golfowy, najkrótszy program wygrywa punkty internetowe.
  • Baw się dobrze!
trochę zmieszany
źródło
3
Nie rozumiem, jak wybieramy jednostkę lub kwotę. Czy zaokrąglamy?
xnor
1
@ xnor dzielimy liczby całkowite i używamy najmniejszej niezerowej wartości wraz z jej jednostką (być może liczbą mnogą). Stąd 59 -> „59 sekund” i 86401 -> „1 dzień”.
Jonathan Allan
5
Witamy w PPCG! Ładne pierwsze wyzwanie. Do wykorzystania w przyszłości jest piaskownica, która jest przydatna do uzyskiwania informacji zwrotnych przed wysłaniem do głównego.
Jonathan Allan
4
Zauważ, że Do X bez Y jest odradzane, podobnie jak nieobserwowalny wymóg programu .
user202729,
1
Jak powinniśmy zaokrąglać liczby? Czy 119 sekund powinno wynosić 1 minutę czy 2 minuty? Co powiesz na 90?
user202729,

Odpowiedzi:

8

Galaretka , 62 bajty

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

Pełny program drukujący wynik.
(Jako monadyczny link zwraca listę liczb całkowitych, po których następują znaki)

Wypróbuj online!

W jaki sposób?

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
źródło
8

C, 194 180 144 128 znaków

Dzięki @gastropher za redukcje kodu. Zapomniałem, że C pozwala na niejawne parametry za pomocą funkcji w stylu K&R! Również dzięki @gmatht za pomysł umieszczenia literałów w środku zamiast tablic. Rozszerzyłem to na postacie, nadużywając korzystania z szerokich znaków / char16_tciągów! Wydaje się jednak, że kompilator nie lubi \1swojej postaci.

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");}

Wypróbuj online!

Oryginalne rozwiązanie

Podzieliłem tablice na osobne linie, aby łatwiej było zobaczyć resztę rozwiązania.

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":"");}

Wypróbuj online!

Prowadząc dzielniki w kolejności od największej do najmniejszej, otrzymujemy najgrubszą jednostkę czasu. Program źle się zachowuje, jeśli dasz mu 0 sekund, ale ponieważ specyfikacja wyraźnie wyklucza tę wartość, uważam, że jest to dopuszczalne.

ErikF
źródło
Można użyć niektórych sztuczek, aby sprowadzić go do 183 bajtów: Wypróbuj online!
gastropner
1
Przepraszam, ten wprowadził błąd. Właściwy z 180 bajtów: Wypróbuj online!
gastropner
@gastropner Myślę, że ostatni ma też błąd. „(d <1)” powinno być „(d <2)” ... lub „(d <= 1)”, ale nie zwariujmy.
gmatht
@gmatht Masz całkowitą rację!
gastropner
OK, ostatni, obiecuję. 164 bajty.
gastropner
7

Perl 5 , 110 bajtów

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

Wypróbuj online!

Ton Hospel
źródło
5

Stax , 54 bajty

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

Uruchom i debuguj

Oto rozpakowana, nie golfowa, ascii reprezentacja tego samego programu.

                            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

Po wykonaniu, ponieważ nie ma innych wyników, górna część stosu jest drukowana niejawnie.

Uruchom ten

rekurencyjny
źródło
5

JavaScript (ES6), 131 bajtów

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

Wypróbuj online!

Arnauld
źródło
Nie byłem świadomy użytej składni (podzielonej ,). Nauczyłem się czegoś nowego. Świetne rozwiązanie.
Makotosan
1
@Makotosan Pamiętaj, że to, co faktycznie jest przekazywane, splitto tablica [',']. Dlatego działa to tylko z funkcjami, które wymuszają przymus na łańcuch.
Arnauld,
3

Java 8, 197 195 157 bajtów

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 bajtów dzięki @ OlivierGrégoire .

Wyjaśnienie:

Wypróbuj 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
źródło
1
157 bajtów . Właśnie grałem w twoje liczby w numery krótsze i poruszałem się /=w razie potrzeby.
Olivier Grégoire
Ulubiony osobisty: 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 bajty), prawdopodobnie dobra baza do gry w golfa.
Olivier Grégoire,
Zaoszczędź 9 bajtów, używając n/7+zamiast (n/=7)+itp.
Neil
@Neil Obawiam się, że to nie zadziała. Na przykład, jeśli wejście jest 2678400, wyjście powinno być 1 monthzamiast 1 months(liczba pojedyncza zamiast liczby mnogiej).
Kevin Cruijssen
Och, subtelne, dzięki za poinformowanie mnie.
Neil
2

Kotlin , 205 203 196 bajtów

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 ""}"}

Wypróbuj online!

Makotosan
źródło
2

T-SQL , 306 bajtów (281 bajtów bez operacji we / wy)

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
źródło
Dwie małe literówki: TRIMnie jest zdefiniowane, prawdopodobnie powinno być LTRIM. Pomiędzy weeki day, masz + , prawdopodobnie powinien być,
Stephan Bauer
Rzeczywiście, zamiast + tego powinno być, i poprawiłem to teraz. Jednak TRIMfunkcja jest zdefiniowana od SQL Server 2017. Dzięki.
Razvan Socol
2

R , 157 bajtów

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="")

Wypróbuj online!

cutjest przydatny, ponieważ dzieli zakresy na factors, które są przechowywane wewnętrznie jako integers, co oznacza, że ​​możemy ich używać również jako indeksów tablic. Prawdopodobnie możemy zrobić coś bardziej sprytnego z nazwami przedziałów czasowych, ale nie mogę jeszcze tego rozgryźć.

Giuseppe
źródło
2

APL + WIN, 88 119 bajtów

Oryginalna wersja pominęła tygodnie i miesiące, jak zauważył Phil H; (

Monituje ekran o liczbę sekund

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'

Wyjaśnienie

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
źródło
Czy ktoś jadł tygodnie i miesiące?
Phil H
@PhilH Cookie Monster? ;) Dzięki. Odpowiedź odpowiednio zmodyfikowana.
Graham
Wyglądało to zbyt schludnie, nawet jak na APL! Jak liczycie bajty? Liczę 119 znaków, a nie bajtów ...
Phil H
@ PhhH Nie rozumiem twojego komentarza najpierw uzgadniamy 119 bajtów, które zmieniłem podczas edytowania odpowiedzi, a powyżej nie mówisz, ile bajtów kwestionujesz
Graham
1

JavaScript (Node.js) , 177 bajtów

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':'')}

Wypróbuj online!

Makotosan
źródło
1

Partia, 185 bajtów

@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
źródło
1

Python 2 , 146 144 bajtów

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]

Wypróbuj online!

2 bajty zapisane dzięki Jonathanowi Allanowi

Chas Brown
źródło
1
if n/xzapisuje bajt.
Jonathan Allan
1
Odwrócenie kolejności i indeksowanie za pomocą 0zapisuje kolejną.
Jonathan Allan
1

PHP , 183 bajtów

<?$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;

Wypróbuj online!

Jo.
źródło
1

Julia 0.6 , 161 bajtów

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

Wypróbuj online!

niczky12
źródło
0

Ruby , 129 bajtów

->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}"}

Wypróbuj online!

Asone Tuhid
źródło
0

Perl 6 / Rakudo 138 bajtów

Jestem pewien, że jest jeszcze wiele do zrobienia, ale na razie

{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"!!"")}

Rozwijać:

{ # 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.
źródło
0

R 336

Praca w toku

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
źródło
0

R 246 bajtów

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","")))}

Wypróbuj online!

To używa formowania czasu zamiast arytmetyki, po prostu do diabła z tym. Może inni mogliby to zmniejszyć?

niczky12
źródło