Dies ist eine von mehreren Herausforderungen, die Calvins Hobbys für die Community hinterlassen haben .
Nehmen Sie eine "Stammbaum beschreibende" Datei mit Zeilen der Form:
[ID] [mother ID] [father ID] [gender] [full name]
so wie das, das den ersten Stammbaum auf http://en.wikipedia.org/wiki/Cousin beschreibt :
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
Schreiben Sie ein Programm oder eine Funktion, die den Dateinamen und zwei IDs aufnimmt und ausgibt, wie diese Personen auf einfachste Weise mit Blut in Verbindung stehen, wobei Sie die gebräuchlichen englischen Namen für Beziehungen verwenden. Die Eingabe kann über STDIN, ARGV oder Funktionsargumente erfolgen, die Ausgabe sollte jedoch über STDOUT erfolgen.
Anmerkungen
- IDs sind positive ganze Zahlen.
?
wird verwendet, wenn die Abstammung nicht bekannt ist.- Angenommen, der Graph ist verbunden und hat keine Zyklen.
- Es kann sein , dass Sie nicht davon ausgehen, dass die Eltern jeder Person vor dieser Person aufgeführt sind (daher könnte die Eltern-ID einer Person größer sein als ihre eigene ID).
- Angenommen, jeder ist entweder männlich oder weiblich und jeder hat genau eine Mutter und genau einen Vater (mit korrektem Geschlecht), obwohl sie möglicherweise unbekannt sind.
- Angenommen, Namen sind eindeutig.
- Namen können Leerzeichen enthalten.
Blutsverwandte
Die folgenden Definitionen von Beziehungen R bestimmen, ob Person A das R oder Person B ist . Wenn zwei Varianten von R aufgelistet sind, ist der erste für weibliche A und die zweite für die männliche A . All dies muss umgesetzt werden. Stimmen mehrere Definitionen überein, ist die frühere zu verwenden. Begriffe in Klammern sind geschlechtsneutrale Begriffe, die nicht implementiert werden müssen, aber in weiteren Definitionen wiederverwendet werden. In Definitionen mit N und M wird angenommen , dass N> 1 und M> 0 sind .
- Tochter / Sohn: A listet B als einen der Elternteile auf.
- Mutter / Vater (Elternteil): B listet A als einen der Elternteile auf.
- Schwester / Bruder (Geschwister): A und B führen die gleiche Mutter und den gleichen Vater auf.
- Halbschwester / Halbbruder (Geschwister): In A und B ist dieselbe Mutter oder derselbe Vater aufgeführt.
- Nichte / Neffe: A listet einen Elternteil auf, der das Geschwister von B ist .
- Tante / Onkel: B ist A 's Nichte oder Neffe.
- Enkelin / Enkel (Enkel): A listet einen Elternteil auf, der B als Elternteil aufführt.
- Großmutter / Großvater (Großeltern): B ist A 's Enkelkind.
- Ur-Nichte / Ur-Neffe: A ist der Enkel von C, der das Geschwister von B ist .
- Großtante / Großonkel: B ist die Großnichte oder der Großneffe von A.
- Urenkel / Sohn (1. Urenkel): A ist ein Enkel von C, der B als Elternteil auflistet .
- Urgroßmutter / Vater (1. Urgroßelternteil): B ist A 's 1. Urenkel.
- N-te Urenkel / Sohn (N-te Urenkel): A ist ein (N-1) -tes Enkelkind von C , das B als Elternteil auflistet .
- Nte Urgroßmutter / Vater (Nte Urgroßmutter): B ist A 's Nte Urenkel.
- N-te Ur-Nichte / Neffe: A ist das (N-1) -te Ur-Enkelkind von C , das das Geschwister von B ist .
- N-te Großtante / Onkel: B ist A 's N-te Großnichte des N-ten Großneffen.
- Cousin: A ist der Enkel von C, der der Großelternteil von B ist .
- N-ter Cousin: A ist der (N-1) Enkel von C, der der (N-1) Großelternteil von B ist .
- Cousin, M-mal entfernt: A ist das Enkelkind von C, der der M-te Großelternteil von B ist, oder A ist das M-te Enkelkind von C, der der Großelternteil von B ist .
- N-ter Cousin, M-mal entfernt: A ist der P- te Urenkel von C, der der Q-te Urgroßvater von B ist , wo
N = min(P,Q) + 1
undM = |P-Q|
.
Für Nth
, Schreib 2nd
, 3rd
, 4th
, 5th
usw.
Für M times
, schreiben once
, twice
, thrice
, 4 times
, 5 times
usw.
Beispiele
Angenommen, die folgende Datei wird verwendet (Sie müssen nicht in der Lage sein, mit mehreren Leerzeichen umzugehen, aber ich habe sie aus Gründen der Lesbarkeit hinzugefügt):
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
Dann sollten die Eingabe-IDs den Ausgaben wie folgt zugeordnet werden:
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.
Ich habe sie von Hand geschrieben. Lassen Sie mich wissen, wenn Sie Fehler entdecken.
Ein weiterer Satz von Testdaten (bereitgestellt von Scott Leadley, alle Fehler sind meine und nicht Martins)
Ptolemäus-Stammbaum
Das Bild ist illustrativ; Die folgenden Daten stammen aus dem Wikipedia-Artikel " Ptolemäische Dynastie ".
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
quelle
Ruby -
189212901247Führen Sie so
ruby relation.rb ID1 ID2 relationship_file
.Ungolfed-Version -
52513416 (derselbe Aufrufbaum hat gerade viel Code gefaltet)Besteht die folgende Testsuite:
quelle
Javascript, 2292
Ich bin sicher, es kann viel weiter golfen werden, alles was ich getan habe, war eine ungolfed Version durch einen Minifier zu stecken.
Sie können die ungolfed-Version hier auf jsFiddle ausführen . Hier ist die Ausgabe für die Beispieldaten:
quelle
Python 3: 1183
Der Dateiname und die IDs der zu beschreibenden Personen werden aus der Standardeingabe in einer einzigen Zeile gelesen.
Der obere Teil des Codes besteht aus Funktionsdefinitionen. Das Skript beginnt auf halber Strecke und verarbeitet zunächst die Eingabe (parst die Datei und weist dann in einem zweiten Durchgang den Eltern Kinder zu).
Nach dem Einrichten der Daten rufen wir die
A
Funktion einmal auf, um eine rekursive Suche zu starten. Das Ergebnis definiert die Beziehung.Der Rest des Codes ist der Beschreibung dieser Beziehung auf Englisch gewidmet. Geschwister und Cousins sind kompliziert (und benutzen lange Schlangen), der Rest ist ziemlich einfach.
Beispiellauf (die zweite Zeile ist meine Eingabe):
Funktions- und Variablennamensschlüssel:
f
: Der Dateiname, aus dem die Daten der Familie gelesen werden.a
: Die ID der Person, deren Beziehung wir benennen.b
: Die ID der Person, zu der die Beziehung definiert ist.t
: Der Stammbaum selbst, als Wörterbuch, das eine Zuordnung von einer ID zu einem 5-Tupel der ID der Mutter, der ID des Vaters, des Geschlechts, des Namens und einer Liste der Kinder enthält.g
: Ein boolescher Wert, der das Geschlecht einer Person widerspiegelta
. Es ist,True
wenn sie männlich sind.u
: Die Anzahl der Generationen vonb
bis zum gemeinsamen Vorfahren vona
undb
(oder 0, wenn dies der Vorfahr vonb
ista
).d
: Die Anzahl der Generationen vona
bis zum gemeinsamen Vorfahren vona
undb
(oder 0, wenn dies der Vorfahr vona
istb
).D(i)
: Suche rekursiv die Nachkommen von Personi
für Persona
. Geben Sie die Tiefe zurück, diea
bei gefunden wurde, oder Keine, wenn sie nicht gefunden wurde.A(i)
: Recursively suchti
undi
‚Abkömmlinge s, aber wenn sie nicht rekursiv Suche gefundeni
‘ s Vorfahren (und ihre Nachkommen) zu. Gibt ein 2-Tupel, wer Werte sindu
undd
oben beschrieben. Wird eine Beziehung über beide Elternteile gefunden, wird diejenige mit der geringsten Anzahl von Generationsschritten (u+d
) bevorzugt. Wenn die Persona
keine Blutsverwandtschaft mit der Person hati
,A(i)
kehrt sie zurückNone
.P(r)
: Geben Sie die Ergebniszeichenfolge inr
Klammern mit den Namen der Personena
und ausb
.O(n)
: Gibt eine Ordnungszahl für die angegebene Zahl zurückn
. Unterstützt nur1 < n < 21
.G(n)
: Gibt einen Präfix-String zurück, dern-1
""2nd great-"
greats " entspricht (z. B. für n = 2`). Gibt eine leere Zeichenfolge für n <= 1 zurück.GG(n)
: Gibt eine Präfixzeichenfolge mit "Nth great-" und "grand" zurück, je nachdem, wie es fürn
Generationen geeignet ist . Gibt eine leere Zeichenfolge für n <= 1 zurück.Ich habe ein paar Abkürzungen im Namen des kürzeren Codes verwendet, die für eine bessere (oder etwas korrektere) Leistung bei großen Genealogien überarbeitet werden könnten. Die
A
Funktion versucht nicht zu vermeiden, dass bereits gesuchte untergeordnete Bäume wiederholt werden, was sie langsamer als nötig macht (obwohl sie für Familien mit angemessener Größe wahrscheinlich immer noch schnell genug ist). DieO
Funktion Griff nicht richtig ordinals größer als 20 (es ist ein heikles Bit alle zu bekommen11th
,21st
und101st
richtig, aber in einem meiner Entwürfe ich es in etwa 25 zusätzliche Bytes haben). Sofern es sich nicht um sehr alte und berühmte Familien handelt (z. B. einige der königlichen Familien Europas), bin ich mir nicht sicher, ob ich der Genauigkeit einer Genealogie vertrauen würde, die sowieso so weit zurückreicht.Andererseits habe ich auch ein paar Stellen übersprungen, an denen ich ein paar Bytes abschneiden konnte. Zum Beispiel könnte ich 3 Bytes einsparen
GG
, indem ich in einen einzelnen Zeichennamen umbenenne , aber esgreat-grand
schien mir sinnvoller, den Namen von abzulehnen.Ich glaube, dass alle Leerzeichen im Code erforderlich sind, aber es ist möglich, dass einige übersprungen werden und ich habe sie nur übersehen (ich habe immer wieder Streulücken in Argumentlisten gefunden, als ich diese Antwort eingetippt habe, aber ich denke, ich ' haben sie jetzt alle bekommen).
Da mein rekursiver Abgleich eine relativ einfache Regel erfordert, für die Beziehungen bevorzugt werden sollen, wenn es mehr als eine gibt, gebe ich in einigen unklaren Fällen mit Inzest zwischen den Generationen nicht genau die gewünschten Ergebnisse an. Wenn zum Beispiel eine Person
a
sowohlb
der Onkel als auch der Großvater einer Person ist , wird mein Kodex die Beziehung zum Großvater bevorzugen, obwohl die Frage besagt, dass die Beziehung zum Onkel Vorrang haben sollte.Hier ist ein Beispiel-Dataset, das das Problem aufdeckt:
Ich vermute, dass bei den meisten Programmen die Beziehungen zwischen Bob und Claire oder zwischen Bob und Danielle Probleme verursachen werden. Sie werden entweder das erste Paar Halbgeschwister anstatt Vater / Tochter nennen oder das letztere Paar eher als Großvater / Enkelin als als Onkel / Nichte bezeichnen. Mein Code macht das letztere und ich sehe keine vernünftige Möglichkeit, es zu ändern, um die angeforderten Ergebnisse zu erhalten, ohne auch das erste Paar falsch zu machen.
quelle
Eine Testsuite. Füllen Sie es in t / relation.t und führen Sie "proof" oder "perl t / relation.t" aus. Derzeit wird davon ausgegangen, dass die Programmdatei "relation.rb" ist.
Es handelt sich um ein Community-Wiki. Sie können also jederzeit Tests hinzufügen. Wenn Sie es ändern, denke ich, dass ein Zeitstempel (oder eine andere offensichtliche Flagge) in Ordnung wäre. Wunschzettel:
quelle