# Examen ALS parcial 1 (c) Baltasar 2022 MIT License <jbgarcia@uvigo.es>
"""
(3 pts.) Implemente la función es_dict_superconjunto(d1, d2).
Se trata de una función que recibe dos diccionarios,
y decide si d1 es un superconjunto de d2.
Un diccionario d1 será superconjunto de otro d2 si
todas las claves de d2 también están en d1, y además,
sus valores asociados son iguales.
La función devolverá una tupla formada
en su primera posición por un valor booleano
(indicando True si es superconjunto o False en caso contrario),
y en la segunda posición otra tupla que contendrá las claves en d2
que no se encuentran en d1 o tienen valores diferentes.
Así, para d1 = {‘a’, 1} y d2 = {‘b’, 2}, devolverá (False, (‘b’,)),
para d1 = {‘a’, 1, ‘b’: 2} y d2 = {‘b’, 2}, devolverá (True, ()),
para d1 = {‘a’, 1, ‘b’: 2} y d2 = {‘a’: 1, ‘b’, 2}, devolverá (True, ()),
y para d1 = {‘a’, 1} y d2 = {‘a’, 42}, devolverá (False, (‘a’,))
"""
def is_dict_superset(d1: dict, d2: dict) -> tuple:
"""Is d1 a superset of d2?"""
diffs = []
for k, v in d2.items():
if (k not in d1.keys()
or v != d1[k]):
diffs.append(k)
toret = len(diffs) == 0
return (toret, tuple(diffs))
"""
(3 pts.) Cree la función evalua_fecha(f: str) -> list,
que acepta una fecha en formato dd/mm/aaaa, d/m/aa, o aaaa/mm/dd.
Nótese que los separadores pueden ser la barra (‘/’), guión (‘-‘)
o incluso un punto (‘.’). Si el año es menor que 100, se le suma 2000.
La función devolverá la fecha como una lista de tres posiciones,
la primera el año, la segunda el mes y la tercera el día.
"""
def eval_date(d: str) -> list:
# Decide separator
sep = '/'
if d.find('-') >= 0:
sep = '-'
if d.find('.') >= 0:
sep = '.'
# Get parts
toret = [int(x) for x in d.split(sep)]
is_iso = True
if toret[0] <= 31:
is_iso = False
if not is_iso:
toret.reverse()
# Add 2000 if needed
if toret[0] < 100:
toret[0] += 2000
return toret
"""
3. (4 pts.) Se necesita desarrollar un programa para explicar recorridos.
Cree la clase Paso, que se construye con una distancia (número real).
De ella derivan las clases Avance
(que además lleva el nombre de la carretera, como texto),
y Desvío de la que a su vez derivan las clases Derecha e Izquierda.
Estas tres clases guardan adicionalmente como texto
el nombre de la salida a tomar,
y la distancia es el punto kilométrico de dicha salida.
La clase Recorrido llevará una lista de objetos Paso,
y dos atributos que guardarán el nombre del punto de salida,
y el nombre del punto de llegada. Ofrecerá los métodos __len__(),
que devuelve el número de elementos del recorrido, inserta(m: Paso),
que inserta al final un nuevo paso, y la propiedad pasos,
que devolverá una lista con los pasos guardados.
El método calcula_distancia() sumará las distancias de los pasos Avance.
Cree inicializadores, métodos __str__() (excepto para Paso)
y propiedades de solo lectura para las clases anteriores.
Tome el siguiente código como referencia.
> r = Recorrido("Ourense", "Vigo")
> r.inserta(Derecha(1.5, "entrada centro"))
> r.inserta(Avance(110, "A-52"))
> r.inserta(Derecha(111, "avda. Madrid"))
> print(f"Número de pasos: {len(r)}")
Número de pasos: 3
> print(r)
Ourense - Vigo (110km): gire a la derecha en km 1.5 por entrada centro,
avance 110km por A-52, gire a la derecha en km 111 por avda. Madrid
"""
class Paso:
def __init__(self, distancia: float):
self._distancia = distancia
@property
def distancia(self):
return self._distancia
class Avance(Paso):
def __init__(self, distancia: float, nombre_carretera: str):
super().__init__(distancia)
self._nombre_carretera = nombre_carretera
@property
def nombre_carretera(self):
return self._nombre_carretera
def __str__(self):
return f"avance {self.distancia}km por {self.nombre_carretera}"
class Desvio(Paso):
def __init__(self, distancia: float, nombre_salida: str):
super().__init__(distancia)
self._nombre_salida = nombre_salida
@property
def nombre_salida(self):
return self._nombre_salida
def __str__(self):
return f"en km {self.distancia} por {self.nombre_salida}"
class Derecha(Desvio):
def __str__(self):
return f"gire a la derecha {super().__str__()}"
class Izquierda(Desvio):
def __str__(self):
return f"gire a la izquierda {super().__str__()}"
class Recorrido:
def __init__(self, comienzo: str, final: str):
self._pasos = []
self._comienzo = comienzo
self._final = final
def inserta(self, p: Paso):
self._pasos.append(p)
def __len__(self) -> int:
return len(self._pasos)
@property
def comienzo(self):
return self._comienzo
@property
def final(self):
return self._final
@property
def pasos(self):
return list(self._pasos)
def calcula_distancia(self):
toret = 0
for p in self._pasos:
if isinstance(p, Avance):
toret += p.distancia
return toret
def __str__(self):
toret = f"{self.comienzo} - {self.final} ({self.calcula_distancia()}km): "
return toret + ", ".join([str(x) for x in self._pasos])
if __name__ == "__main__":
d1 = {'a': 1, 'b': 2}
d2 = {'a': 1}
d3 = dict(d1)
d4 = {'c': 3}
d5 = {'a': 42}
print(f"{d1} superset {d2}: {is_dict_superset(d1, d2)}")
print(f"{d1} superset {d3}: {is_dict_superset(d1, d3)}")
print(f"{d1} superset {d4}: {is_dict_superset(d1, d4)}")
print(f"{d2} superset {d1}: {is_dict_superset(d2, d1)}")
print(f"{d3} superset {d1}: {is_dict_superset(d3, d1)}")
print(f"{d4} superset {d1}: {is_dict_superset(d4, d1)}")
print(f"{d2} superset {d5}: {is_dict_superset(d2, d5)}")
r = Recorrido("Ourense", "Vigo")
r.inserta(Derecha(1.5, "entrada centro"))
r.inserta(Avance(110, "A-52"))
r.inserta(Derecha(111, "avda. Madrid"))
print(f"Número de pasos: {len(r)}")
print(r)
print(f"eval_date('2022/02/01') = {eval_date('2022/02/01')}")
print(f"eval_date('2022/2/1') = {eval_date('2022/2/1')}")
print(f"eval_date('1-2-22') = {eval_date('1-2-22')}")