Este es uno de los varios desafíos que Calvin's Hobbies dejó para la comunidad .
Tome un archivo de "árbol genealógico que describa" con líneas del formulario:
[ID] [mother ID] [father ID] [gender] [full name]
como este que describe el primer árbol genealógico en 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
Escriba un programa o función que tome el nombre del archivo y dos ID y muestre cómo esas personas están relacionadas con la sangre en términos simples, utilizando los nombres comunes en inglés para las relaciones. La entrada puede ser a través de STDIN, ARGV o argumentos de función, pero la salida debe ser a STDOUT.
Notas
- Los ID son enteros positivos.
?
se usa cuando se desconoce la paternidad.- Suponga que el gráfico estará conectado y no tiene ciclos.
- Es posible que no asumir que los padres de cada persona se enumeran antes de esa persona (por lo de una persona Identificación padre podría ser mayor que su propio ID).
- Suponga que todos son hombres o mujeres y que todos tienen exactamente una madre y exactamente un padre (del género correcto), aunque pueden ser desconocidos.
- Asuma que los nombres son únicos.
- Los nombres pueden tener espacios en ellos.
Relaciones de sangre
Las siguientes definiciones de relaciones R determinar si la persona A es la R o persona B . Si se enumeran dos variantes de R , la primera es para A hembra y la segunda para A macho . Todo esto necesita ser implementado. Si coinciden varias definiciones, se utilizará la anterior. Los términos entre paréntesis son términos neutrales al género, que no necesitan ser implementados pero serán reutilizados en definiciones adicionales. En las definiciones que involucran N y M , suponga N> 1 y M> 0 .
- hija / hijo: A enumera a B como padre o madre.
- madre / padre (padre): B enumera A como padre o madre.
- hermana / hermano (hermano): A y B enumeran la misma madre y padre.
- media hermana / medio hermano (hermano): A y B enumeran la misma madre o el mismo padre.
- sobrina / sobrino: A las listas de un padre que es el hermano de B .
- tía / tío: B es sobrina o sobrino de A.
- nieta / nieto (nieto): A enumera a un padre que enumera a B como su padre.
- abuela / abuelo (abuelo): B es el nieto de A.
- sobrina nieta / sobrino nieto: Una es el nieto de C , que es el hermano de B .
- tía abuela / tío abuelo: B es la sobrina nieta o sobrino nieto de A.
- bisnieta / hijo (1er bisnieto): A es un nieto de C que enumera a B como su padre.
- bisabuela / padre (1er bisabuelo): B es el 1er bisnieto de A.
- Enésima bisnieta / hijo (enésimo bisnieto): A es un (N-1) nieto de C que enumera a B como su padre.
- Enésimo bisabuela / padre (enésimo bisabuelo): B es el enésimo bisnieto de A.
- N-ésimo gran-sobrina / sobrino: A es el (N-1) -ésimo bisnieto de C que es el hermano de B .
- Enésima tía / tío: B es A 's enésima sobrina nieta del enésimo sobrino-nieto.
- primo: Una es el nieto de C que es el abuelo de B .
- Primo N-ésimo: A es el (N-1) -ésimo nieto de C que es el (N-1) -ésimo abuelo de B .
- primo, M veces eliminado: A es el nieto de C que es el abuelo Mes de B o A es el nieto Mes de C que es el abuelo de B .
- Primo enésimo, M veces eliminado: A es el enésimo bisnieto de C que es el enésimo bisabuelo de B , donde
N = min(P,Q) + 1
yM = |P-Q|
.
Para Nth
, escritura 2nd
, 3rd
, 4th
, 5th
etc.
Para M times
, escritura once
, twice
, thrice
, 4 times
, 5 times
etc.
Ejemplos
Suponga que se usa el siguiente archivo (no tiene que ser capaz de lidiar con múltiples espacios, pero los agregué para legibilidad):
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
Luego, las ID de entrada deben correlacionarse con las salidas de la siguiente manera:
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.
Los escribí a mano, así que avíseme si detecta algún error.
Otro conjunto de datos de prueba (proporcionado por Scott Leadley, cualquier error es mío y no de Martin)
Árbol genealógico de Ptolomeo
La imagen es ilustrativa; los datos a continuación provienen del artículo de Wikipedia " Dinastía ptolemaica ".
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
fuente
Rubí -
189212901247Corre como
ruby relation.rb ID1 ID2 relationship_file
.Versión sin golf -
52513416 (mismo árbol de llamadas, solo hice un montón de plegado de código)Pasa el siguiente conjunto de pruebas:
fuente
Javascript, 2292
Estoy seguro de que se puede jugar mucho más, todo lo que hice fue poner una versión sin golf a través de un minificador.
Puede ejecutar la versión sin golf aquí en jsFiddle . Aquí está la salida para los datos de ejemplo:
fuente
Pitón 3: 1183
El nombre de archivo y las ID de las personas que se describirán se leen desde la entrada estándar en una sola línea.
La parte superior del código son las definiciones de funciones. El script comienza a mitad de camino, y primero trabaja en el procesamiento de la entrada (analizando el archivo, luego asignando hijos a sus padres en una segunda pasada).
Después de configurar los datos, llamamos a la
A
función una vez para iniciar una búsqueda recursiva. El resultado define la relación.El resto del código está dedicado a describir esa relación en inglés. Los hermanos y primos son complicados (y usan líneas largas), el resto es bastante sencillo.
Ejemplo de ejecución (la segunda línea es mi entrada):
Función y clave de nombre de variable:
f
: El nombre de archivo del que se leen los datos de la familia.a
: La identificación de la persona cuya relación estamos nombrando.b
: El ID de la persona con la que se define la relación.t
: El árbol genealógico en sí mismo, como un mapeo de diccionario de una identificación a una tupla de 5 de la identificación de la madre, identificación del padre, sexo, nombre y una lista de hijos.g
: Un valor booleano que refleja el género de la personaa
. EsTrue
si son hombres.u
: El número de generaciones desdeb
hasta el ancestro común dea
yb
(o 0 sib
esa
el ancestro de).d
: El número de generaciones desdea
hasta el ancestro común dea
yb
(o 0 sia
esb
el ancestro de).D(i)
: Recursivamente busca a los descendientes de personai
por personaa
. Devuelve la profundidada
encontrada en, o Ninguno si no se encontró.A(i)
: Búsqueda recursivai
yi
descendientes de, pero si no se encuentra recursivamente, busque también ai
los antepasados (y sus descendientes). Devuelve una tupla de 2, cuyos valores sonu
y sed
describen anteriormente. Si se encuentra una relación a través de ambos padres,u+d
se prefiere el que tenga el menor número de pasos generacionales ( ). Si la personaa
no tiene una relación de sangre con la personai
,A(i)
regresaNone
.P(r)
: Imprimir cadena de resultadosr
entre corchetes por los nombres de personasa
yb
.O(n)
: Devuelve una cadena ordinal para el número dadon
. Solo apoyos1 < n < 21
.G(n)
: Devuelve una cadena de prefijo equivalente an-1
"grandes" (por ejemplo,"2nd great-"
para n = 2`). Devolverá una cadena vacía para n <= 1.GG(n)
: Devuelve una cadena de prefijo con "Nth great-" y "grand", según corresponda paran
generaciones. Devolverá una cadena vacía para n <= 1.Tomé algunos atajos en nombre de un código más corto que podría revisarse para un mejor rendimiento (o un poco más correcto) en genealogías grandes. La
A
función no hace ningún intento de evitar la recurrencia de árboles secundarios que ya se han buscado, lo que lo hace más lento de lo necesario (aunque probablemente sea lo suficientemente rápido para familias de tamaño razonable). LaO
función no controla correctamente los ordinales mayor de 20 (que es un poco difícil de conseguir todos11th
,21st
y101st
la derecha, pero en uno de mis proyectos de versiones lo hice en unos 25 bytes adicionales). A menos que se trate de familias muy antiguas y famosas (por ejemplo, algunas de las familias reales de Europa), no estoy seguro de confiar en la precisión de una genealogía que se remonta a esa distancia de todos modos.Por otro lado, también he omitido algunos lugares donde podría reducir algunos bytes. Por ejemplo, podría ahorrar 3 bytes cambiando el nombre
GG
a un solo nombre de personaje, pero basar el nombre en algo megreat-grand
pareció más valioso.Creo que se requieren todos los espacios en blanco en el código, pero es posible que se puedan omitir algunos y simplemente los he omitido (seguí encontrando espacios vacíos en las listas de argumentos mientras escribía esta respuesta, pero creo que ' los tengo todos ahora).
Debido a que mi correspondencia recursiva requiere una regla relativamente simple para qué relaciones preferir si hay más de una, no doy exactamente los resultados solicitados en algunos casos oscuros que involucran incesto intergeneracional. Por ejemplo, si la persona
a
esb
tío y abuelo de la persona, mi código preferirá la relación del abuelo a pesar de la pregunta que dice que la relación del tío debería tener mayor prioridad.Aquí hay un conjunto de datos de ejemplo que expone el problema:
Sospecho que para la mayoría de los programas, las relaciones entre Bob y Claire o entre Bob y Danielle causarán problemas. Llamarán al primer par de medio hermanos en lugar de padre / hija o describirán al último par como abuelo / nieta en lugar de tío / sobrina. Mi código hace lo último, y no veo ninguna forma razonable de cambiarlo para obtener los resultados solicitados sin también obtener el primer par incorrecto.
fuente
Un conjunto de pruebas. Rellenarlo en t / relacion.t y ejecutar "probar" o "perl t / relacion.t". Actualmente se supone que el archivo del programa es "relacion.rb".
Es una wiki comunitaria, así que siéntase libre de agregar pruebas. Si lo cambia, creo que una marca de tiempo (o alguna otra marca obvia) estaría en orden. Lista de deseos:
fuente