To jedno z kilku wyzwań pozostawionych społeczności przez Hobby Calvina .
Weź plik „drzewa genealogicznego opisującego” z wierszami formularza:
[ID] [mother ID] [father ID] [gender] [full name]
taki jak ten, który opisuje pierwsze drzewo genealogiczne na stronie http://en.wikipedia.org/wiki/Cousin :
1 ? ? M Adam
2 ? ? F Agatha
3 ? ? M Bill
4 2 1 F Betty
5 2 1 M Charles
6 ? ? F Corinda
7 3 4 M David
8 6 5 F Emma
Napisz program lub funkcję, która pobierze nazwę pliku i dwa identyfikatory oraz wyświetli, w jaki sposób osoby te są powiązane z krwią w najprostszy sposób, używając wspólnych angielskich nazw dla relacji. Dane wejściowe mogą być przekazywane za pośrednictwem argumentów STDIN, ARGV lub funkcji, ale dane wyjściowe powinny być przesyłane do STDOUT.
Notatki
- Identyfikatory są dodatnimi liczbami całkowitymi.
?
jest stosowany, gdy pochodzenie nie jest znane.- Załóżmy, że wykres zostanie podłączony i nie ma cykli.
- Być może nie przyjąć, że rodzice każdej osoby są wymienione przed tą osobę (a więc osoba rodzic ID może być większa niż własnego ID).
- Załóżmy, że każdy jest mężczyzną lub kobietą i każdy ma dokładnie jedną matkę i dokładnie jednego ojca (odpowiedniej płci), chociaż mogą być nieznani.
- Załóżmy, że nazwy są unikalne.
- W nazwach mogą znajdować się spacje.
Relacje z krwią
Poniższe definicje relacji R określić, czy osoba jest R lub osoba B . Jeśli dwa warianty R wymienione pierwsze dla kobiet A , a drugi męskiej A . Wszystkie te muszą zostać wdrożone. Jeśli pasuje wiele definicji, należy użyć wcześniejszej. Terminy w nawiasach są terminami neutralnymi pod względem płci, które nie muszą być wdrażane, ale zostaną ponownie wykorzystane w dalszych definicjach. W definicjach obejmujących N i M załóżmy, że N> 1 i M> 0 .
- córka / syn: A wymienia B jako jednego z rodziców.
- matka / ojciec (rodzic): B wymienia A jako jednego z rodziców.
- siostra / brat (rodzeństwo): A i B wymieniają tę samą matkę i ojca.
- przyrodnia siostra / przyrodni brat (rodzeństwo): A i B wymieniają tę samą matkę lub tego samego ojca.
- siostrzenica / bratanek: A list rodzic, który jest rodzeństwo B .
- ciocia / wujek: B jest siostrzenicą lub siostrzeńcem A.
- wnuczka / wnuk (wnuk): A wymienia rodzica, który wymienia B jako rodzica.
- babcia / dziadek (dziadek): B jest wnukiem A.
- pra-siostrzenicą / pra-bratanek: jest wnukiem C , który jest rodzeństwo B .
- pra-ciocia / pra-wujek: B jest pra-siostrzenicą lub pra-siostrzeńcem A.
- prawnuczka / syn (1. prawnuczka): A jest wnukiem C, który wymienia B jako swojego rodzica.
- prababcia / ojciec (1. prapradziadek): B jest 1. praprawnukiem A.
- N-prawnuczka / syn (N-prawnuczka): A jest (N-1) wnuczką C, która wymienia B jako swojego rodzica.
- Pn prababcia / ojciec (n-ty pra-dziadek): B jest „s nth prawnuk.
- N-ty pra siostrzenica / bratanek: wynosi (n-1) prawnukowie C, który jest rodzeństwa B .
- N-ty pra-ciotka / wujek: B jest „s nth pra-siostrzenicą Nth pra-siostrzeńca.
- kuzyn: jest wnukiem C , który jest dziadkiem z pensjonatów .
- N-ty kuzyn: wynosi (n-1) wnukiem C, który jest (N-1) dziadków B .
- Kuzynie M razy usunięte: jest wnukiem C, który jest rodzicielskiego mc od B lub jest wnuczek mc z C, który jest dziadków B .
- N-ty kuzyn, M razy usunięty: A to piąty prawnuk C, który jest Q-tym pradziadkiem B , gdzie
N = min(P,Q) + 1
iM = |P-Q|
.
Na Nth
, pisać 2nd
, 3rd
, 4th
, 5th
itd.
Na M times
, pisać once
, twice
, thrice
, 4 times
, 5 times
itd.
Przykłady
Załóżmy, że użyto następującego pliku (nie musisz mieć możliwości radzenia sobie z wieloma spacjami, ale dodałem je dla czytelności):
1 ? ? F Agatha
2 ? ? M Adam
3 ? ? F Betty
4 1 2 M Bertrand
5 1 2 F Charlotte
6 ? ? M Carl
7 ? ? F Daisy
8 3 4 M David
9 5 6 F Emma
10 ? ? M Edward
11 ? ? F Freya
12 7 8 M Fred
13 9 10 F Grace
14 ? ? M Gerald
15 ? ? F Hillary
16 11 12 M Herbert
17 13 14 F Jane
18 ? ? M James
19 15 16 F Kate
20 17 18 M Larry
21 ? 18 F Mary
Następnie identyfikatory wejściowe powinny być mapowane na wyjścia w następujący sposób:
1 2 --> Agatha is not a blood relative to Adam.
8 3 --> David is the son of Betty.
9 13 --> Emma is the mother of Grace.
4 5 --> Bertrand is the brother of Charlotte.
9 4 --> Emma is the niece of Bertrand.
5 8 --> Charlotte is the aunt of David.
16 7 --> Herbert is the grandson of Daisy.
1 9 --> Agatha is the grandmother Emma.
12 5 --> Fred is the great-nephew of Charlotte.
4 13 --> Bertrand is the great-uncle of Grace.
16 3 --> Herbert is the great-grandson of Betty.
6 17 --> Carl is the great-grandfather of Jane.
19 2 --> Kate is the 3rd great-granddaughter of Adam.
1 17 --> Agatha is the 2nd great-grandmother of Jane.
20 4 --> Larry is the 3rd great-nephew of Bertrand.
5 16 --> Charlotte is the 2nd great-aunt of Herbert.
8 9 --> David is the cousin of Emma.
19 20 --> Kate is the 4th cousin of Larry.
16 9 --> Herbert is the cousin, twice removed, of Emma.
12 17 --> Fred is the 2nd cousin, once removed, of Jane.
21 20 --> Mary is the half-sister of Larry.
Napisałem je ręcznie, więc daj mi znać, jeśli zauważysz jakieś błędy.
Kolejny zestaw danych testowych (dostarczonych przez Scotta Leadleya, wszelkie błędy są moje, a nie Martina)
Drzewo genealogiczne Ptolemeusza
Zdjęcie jest poglądowe; dane poniżej pochodzą z artykułu w Wikipedii „ Dynastia Ptolemeuszy ”.
1 ? ? F Berenice I of Egypt
2 ? ? M Ptolemy I Soter
41 1 2 F Arsinoe II of Egypt
3 1 2 M Ptolemy II Philadelphus
4 ? ? F Arsinoe I of Egypt
5 ? ? M Philip
6 4 3 M Ptolemy III Euergetes
7 1 5 F Magas of Cyrene
8 7 ? F Berenice II
9 8 6 M Ptolemy IV Philopator
10 8 6 F Arsinoe III of Egypt
11 10 9 M Ptolemy V Epiphanes
12 ? ? F Cleopatra I of Egypt
13 12 11 M Ptolemy VI Philometor
14 12 11 F Cleopatra II
15 12 11 M Ptolemy VIII Physcon
19 ? ? F Eirene
16 14 13 M Ptolemy VII Neos Philopator
17 14 13 F Cleopatra III
18 14 15 M Ptolemy Memphites
20 19 15 M Ptolemy Apion
21 17 15 F Cleopatra IV
22 17 15 M Ptolemy IX Lathyros
23 17 15 F Cleopatra Selene I
24 17 15 M Ptolemy X Alexander I
25 23 22 F Berenice III of Egypt
26 23 24 M Ptolemy XI Alexander II
27 21 22 M Ptolemy XII Auletes
28 25 24 F Cleopatra V of Egypt
29 28 27 F Cleopatra VI of Egypt
30 28 27 F Berenice IV of Egypt
31 28 27 M Ptolemy XIII Theos Philopator
32 28 27 F Cleopatra VII Thea Philopator
33 28 27 M Ptolemy XIV
34 28 27 F Arsinoe IV of Egypt
35 ? ? M Julius Caesar
37 32 35 M Ptolemy XV Caesarion
36 ? ? M Mark Anthony
38 32 36 M Alexander Helios
39 32 36 M Ptolemy XVI Philadelphus
40 32 36 F Cleopatra Selene II
źródło
Rubin -
189212901247Uruchom jako
ruby relation.rb ID1 ID2 relationship_file
.Wersja bez golfa -
52513416 (to samo drzewo wywołań, po prostu dużo zwijania kodu)Przechodzi następujący zestaw testów:
źródło
JavaScript, 2292
Jestem pewien, że można grać w golfa znacznie dalej, wszystko, co zrobiłem, to przełożenie wersji bez golfa przez minifikator.
Możesz uruchomić wersję bez golfa tutaj na jsFiddle . Oto dane wyjściowe dla przykładowych danych:
źródło
Python 3: 1183
Nazwa pliku i identyfikatory opisywanych osób są odczytywane ze standardowego wejścia w jednym wierszu.
Górna część kodu to definicje funkcji. Skrypt rozpoczyna się w połowie drogi i najpierw pracuje nad przetwarzaniem danych wejściowych (analizowanie pliku, a następnie przypisywanie dzieci do rodziców w drugim przebiegu).
Po skonfigurowaniu danych wywołujemy tę
A
funkcję raz, aby rozpocząć wyszukiwanie rekurencyjne. Wynik określa relację.Reszta kodu poświęcona jest opisaniu tego związku w języku angielskim. Rodzeństwo i kuzyni są skomplikowani (i używają długich linii), reszta jest dość prosta.
Przykład uruchomienia (drugi wiersz to moje dane wejściowe):
Klucz funkcji i nazwy zmiennej:
f
: Nazwa pliku, z którego odczytywane są dane rodziny.a
: Identyfikator osoby, której związek nazywamy.b
: Identyfikator osoby, z którą relacja jest zdefiniowana względem.t
: Samo drzewo genealogiczne, jako słownik mapujący od identyfikatora do 5-krotności identyfikatora matki, identyfikatora ojca, płci, imienia i listy dzieci.g
: Wartość logiczna odzwierciedlająca płeć osobya
. To jest,True
jeśli są mężczyzną.u
: Liczba pokoleń odb
wspólnego przodkaa
ib
(lub 0, jeślib
jesta
przodkiem).d
: Liczba pokoleń oda
wspólnego przodkaa
ib
(lub 0, jeślia
jestb
przodkiem).D(i)
: Rekurencyjnie szukaj potomków osoby wi
poszukiwaniu osobya
. Zwraca głębokość, wa
której znaleziono, lub Brak, jeśli nie została znaleziona.A(i)
: Szukaj rekurencyjniei
ii
potomkowie, ale jeśli nie znaleziono rekurencyjnie szukaji
przodków (i ich potomków). Zwraca 2-krotkę, której wartości sąu
i zostałyd
opisane powyżej. Jeśli związek zostanie znaleziony przez oboje rodziców,u+d
preferowany jest ten, który ma najmniejszą liczbę kroków pokoleniowych ( ). Jeśli dana osobaa
nie ma związku krwi z osobąi
,A(i)
powracaNone
.P(r)
: Wydrukuj ciąg wyników wr
nawiasach nazwisk osóba
ib
.O(n)
: Zwraca ciąg porządkowy dla podanej liczbyn
. Obsługuje tylko1 < n < 21
.G(n)
: Zwraca ciąg prefiksu odpowiadającyn-1
„greats” (np."2nd great-"
Dla n = 2`). Zwróci pusty ciąg dla n <= 1.GG(n)
: Zwraca ciąg prefiksu zawierający „N-ty wielki-” i „wielki”, odpowiedni dlan
pokoleń. Zwróci pusty ciąg dla n <= 1.Zrobiłem kilka skrótów w imię krótszego kodu, który można poprawić, aby uzyskać lepszą (lub nieco bardziej poprawną) wydajność w przypadku dużych genealogii. Ta
A
funkcja nie usiłuje uniknąć rekurencji w drzewach potomnych, które zostały już przeszukane, co czyni ją wolniejszą niż to konieczne (choć prawdopodobnie nadal wystarczająco szybką dla rodzin o rozsądnych rozmiarach).O
Funkcja nie obsługuje poprawnie porządkowych większa niż 20 (jest to trochę skomplikowane, aby dostać wszystko11th
,21st
i101st
słusznie, ale w jednym z moich projektów wersjach Zrobiłem to w około 25 dodatkowych bajtów). Chyba że masz do czynienia z bardzo starymi i sławnymi rodzinami (np. Niektórymi rodzinami królewskimi w Europie), nie jestem pewien, czy ufałbym dokładności genealogii, która i tak sięga tak daleko.Z drugiej strony pominąłem też kilka miejsc, w których mogłem ogolić kilka bajtów. Na przykład mogłem zaoszczędzić 3 bajty, zmieniając nazwę
GG
na nazwę jednego znaku, ale oparcie nazwygreat-grand
wydawało mi się bardziej warte zachodu.Uważam, że wszystkie białe znaki w kodzie są wymagane, ale możliwe jest, że niektóre można pominąć, a ja po prostu za nimi tęskniłem (w trakcie pisania tej odpowiedzi znajdowałem zbłąkane spacje na listach argumentów, ale myślę, że „ mam je wszystkie teraz).
Ponieważ moje rekurencyjne dopasowywanie wymaga stosunkowo prostej reguły, dla której preferowane są relacje, jeśli istnieje więcej niż jedna, nie podam dokładnie żądanych wyników w niektórych niejasnych przypadkach obejmujących kazirodztwo międzypokoleniowe. Na przykład, jeśli dana osoba
a
jest zarównob
wujkiem, jak i dziadkiem osoby, mój kod preferuje relację dziadka, pomimo pytania, że relacja wujka powinna mieć wyższy priorytet.Oto przykładowy zestaw danych, który ujawnia problem:
Podejrzewam, że w przypadku większości programów relacje między Bobem a Claire lub między Bobem a Danielle będą powodować problemy. Będą albo nazywać pierwszą parę przyrodnim rodzeństwem, a nie ojcem / córką, lub będą opisywać drugą parę jako dziadek / wnuczka, a nie wujek / siostrzenica. Mój kod robi to drugie i nie widzę żadnego rozsądnego sposobu, aby go zmienić, aby uzyskać żądane wyniki bez pomyłki pierwszej pary.
źródło
Zestaw testowy. Umieść go w t / relations.t i uruchom „udowodnij” lub „perl t / relations.t”. Obecnie zakłada się, że plik programu to „relations.rb”.
To wiki społeczności, więc dodaj testy. Jeśli to zmienisz, myślę, że znacznik czasu (lub inna oczywista flaga) byłaby w porządku. Lista życzeń:
źródło