Łączone urodziny 100 lat

26

Niedawno zsumowałem wiek siebie, mojej żony i dzieci i zdałem sobie sprawę, że w pewnym momencie w niezbyt odległej przyszłości wszystkie nasze czasy sumują się dokładnie do 100 lat.

Wyzwanie

W przypadku danych wejściowych składających się z łącznego (całkowitego) wieku i listy dat urodzenia należy podać datę, w której wszystkie połączone wieku sumują się do podanej sumy.

  1. Łączny wiek wejściowy (w latach) będzie dodatnią liczbą całkowitą
  2. Wprowadzana lista dat urodzenia będzie listą (niezależnie od formatu dogodnego dla twojego języka) dat, które muszą zawierać numeryczną reprezentację dnia, miesiąca i roku. Liczba dni od określonej epoki jest niedopuszczalna. Możesz założyć, że lista dat wprowadzania jest posortowana w porządku chronologicznym.
  3. Dane wyjściowe będą pojedynczą datą w tym samym formacie co daty wejściowe
  4. Do celów połączonego wieku za 1 rok uważa się dokładnie 365,25 dnia
  5. W przypadku niektórych danych wejściowych niemożliwe będzie znalezienie daty po wszystkich datach urodzenia, gdy wszystkie zsumują się do łącznego wieku. Weźmy na przykład dwie daty urodzenia w odstępie 20 lat, ale chcemy połączyć 10 lat. W takim przypadku wynikiem będzie 10. urodziny starszej daty urodzenia. Innymi słowy, poszczególne grupy wiekowe uważa się za 0 dla wszystkich dat przed datą urodzenia tej osoby
  6. Produkcja globalna będzie pierwszą datą, w której połączony wiek sumuje się co najmniej z wiekiem wejściowym
  7. Możesz korzystać z wbudowanych funkcji
  8. Musisz wspierać daty sięgające 1970/01/01.

Przykłady

Tutaj podaję wszystkie daty w formacie RRRR / MM / DD, ale możesz wybrać dowolny format.

Input                                               Output

 10  2000/01/01                                     2010/01/01
100  1975/03/05,1978/07/23,2008/11/12,2012/12/20    2018/11/22
100  1975/03/06,1978/07/23,2008/11/12,2012/12/20    2018/11/23
100  1975/03/09,1978/07/23,2008/11/12,2012/12/20    2018/11/23
100  1975/03/10,1978/07/23,2008/11/12,2012/12/20    2018/11/24
  3  1990/08/01,1995/07/02                          1993/08/01
 50  1975/03/05,1978/07/23,2008/11/12,2012/12/20    2001/11/13

Należy zauważyć, że w dwóch ostatnich przykładach data wyjściowa mieści się w zakresie dat wejściowych, zgodnie z regułą 5.

Cyfrowa trauma
źródło
1
@TimmyD. Zasada 7 jest zasadą may , więc nie musisz jej przestrzegać, jeśli nie chcesz. Podejrzewam, że funkcje daty i godziny będą przydatne do analizowania dat wejściowych i formatowania dat wyjściowych. YMMV.
Cyfrowa trauma
5
Zasada 7 to maja regułą. Można go bezpiecznie zignorować w tym miesiącu (i przez następne pół roku).
Martin Ender
Realistycznie myślę, że rodzina sprawdza na każde urodziny, licząc lata jako liczby całkowite i nie próbując podsumować dni (z 0,25, aby skomplikować sprawę).
edc65
@ edc65 Kto kiedykolwiek pozwolił rzeczywistości stanąć na drodze do dobrego wyzwania PPCG? ;-)
Cyfrowy uraz

Odpowiedzi:

4

Mathematica 138 107 237 bajtów

Moje pierwsze próby były niechlujne i niegodne. Powinno to ogólnie działać, pod warunkiem, że daty urodzenia podano w kolejności od najwcześniejszego do najpóźniejszego, jak w przypadkach testowych.

Przypadki testowe zostały dobrze wybrane i trudne do prawidłowego wdrożenia. Kod okazał się znacznie dłuższy, niż się spodziewałem.

Ogólna logika jest taka

  1. Rozwiąż dla x (w dniach) tak, aby odległość od x do każdej daty urodzenia sumowała się do docelowego upływu czasu (np. 100 lat przeliczone na dni).
  2. Jeśli najwcześniejsza data + x dni> ostatnia data urodzenia, usuń najnowszą datę urodzenia i powtórz krok (1), w przeciwnym razie przejdź do (3).
  3. Zwrot (najwcześniejsza data + x dni)

t_~f~d_:=If[DateDifference[a=DateObject[DatePlus[d[[1]],Solve[t 365.25==Tr@(x-Join[{0},
QuantityMagnitude@(DateDifference[d[[1]],#,"Day"]&/@Rest@d)]),{x}][[1,1,2]]]/.
{y_,m_,n_,h_}:>{y,m,n+1}],d[[-1]]]>Quantity[0,"Days"],f[t,Most@d],a]

Przypadki testowe

f[10, {{2000, 1, 1}}]
f[100, {{1975, 3, 5}, {1978, 7, 23}, {2008, 11, 12}, {2012, 12, 20}}]
f[100, {{1975, 3, 6}, {1978, 7, 23}, {2008, 11, 12}, {2012, 12, 20}}]
f[100, {{1975, 3, 9}, {1978, 7, 23}, {2008, 11, 12}, {2012, 12, 20}}]
f[100, {{1975, 3, 10}, {1978, 7, 23}, {2008, 11, 12}, {2012, 12,  20}}]
f[3, {{1990, 8, 1}, {1995, 7, 2}}]
f[50, {{1975, 3, 5}, {1978, 7, 23}, {2008, 11, 12}, {2012, 12, 20}}]

zdjęcia

DavidC
źródło
Nie potrzebujesz też miejsca.
LegionMammal978
1

PowerShell, 145 125 bajtów

param($a,$b)$c=@();$b|%{$c+=date $_};$t=$a*365.25;$d=$c[0];while($t-gt0){$c|%{if($_-le$d){$t--}};$d=$d.AddDays(1)}"{0:d}"-f$d

Dość trudne wyzwanie, ale po zrozumieniu stosunkowo proste.

Rozszerzony i skomentowany:

param($a,$b)          # Take our input
$c=@()                # Make a new array $c
$b|%{$c+=date $_}     # Change our input array $b of strings into dates, store in $c
$t=$a*365.25          # Target number of days we need to account for
$d=$c[0]              # Our starting date, also our cumulative date for output
while($t-gt0){        # While we still have days remaining
  $c|%{               # Iterate through our birthdays
    if($_-le$d){$t--} # If the birthday is less than our cumulutive day, subtract a day
  }
  $d=$d.AddDays(1)    # We've accounted for another day, so increment our cumulative day
}
"{0:d}"-f$d           # Format output

Przykład:

Dane wejściowe muszą zawierać jawnie sformatowaną tablicę reprezentacji ciągów-dat. Dane wyjściowe mają MM/DD/YYYYformat (domyślny dla lokalizacji en-us w PowerShell).

PS C:\Tools\Scripts\golfing> .\combined-100-year-birthday.ps1 50 @('03/05/1975','07/23/1978','11/12/2008','12/20/2012')
11/13/2001

Edytuj - gra w golfa 20 bajtów, zmieniając sposób, w jaki iterujemy przez urodziny, i używając while zamiast do / do

AdmBorkBork
źródło
0

PHP, 220 bajtów

Dodałem kilka nowych linii dla czytelności.

function c($y,$s){for($d=$y*365.25;++$i<count($l=array_map(date_create,$s));)$d+=
$l[0]->diff($l[$i])->days;($l[$i-1]>$r=$l[0]->add(new DateInterval(P.ceil($d/$i).D)
))?c($y,array_slice($s,0,-1)):print$r->format('Y/m/d');}

Ideone

Oto wersja bez golfa:

function printCombinedBirthday($combinedAgeInYears, $listOfBirthDatesStrings)
{
    $combinedAgeInDays = $combinedAgeInYears * 365.25;
    $listOfBirthDates = array_map('date_create', $listOfBirthDatesStrings);
    $numberOfBirthDates = count($listOfBirthDates);

    for ($i = 0; $i < $numberOfBirthDates; ++$i) {
        $combinedAgeInDays += $listOfBirthDates[0]->diff($listOfBirthDates[$i])->days;
    }

    $combinedAgeInDays = ceil($combinedAgeInDays / $numberOfBirthDates);
    $interval = new DateInterval('P'. $combinedAgeInDays .'D');
    $result = $listOfBirthDates[0]->add($interval);

    if ($listOfBirthDates[$numberOfBirthDates - 1] > $result)
    {
        printCombinedBirthday(
            $combinedAgeInYears,
            array_slice($listOfBirthDatesStrings, 0, -1)
        );
    }
    else {
        echo $result->format('Y/m/d');
    }
}
Czarna dziura
źródło