TAD de los conjuntos - Transformaciones entre conjuntos y listas
Utilizando el tipo abstracto de datos de los conjuntos definir las funciones
listaAconjunto :: [a] -> Conj a conjuntoAlista :: Conj a -> [a]
tales que
-
listaAconjunto xs
es el conjunto formado por los elementos dexs
. Por ejemplo,
λ> listaAconjunto [3, 2, 5] {2, 3, 5}
-
conjuntoAlista c
es la lista formada por los elementos del conjuntoc
. Por ejemplo,
λ> conjuntoAlista (inserta 5 (inserta 2 (inserta 3 vacio))) [2,3,5]
Comprobar con QuickCheck que ambas funciones son inversa; es decir,
conjuntoAlista (listaAconjunto xs) = sort (nub xs) listaAconjunto (conjuntoAlista c) = c
Soluciones
A continuación se muestran las soluciones en Haskell y las soluciones en Python.
Soluciones en Haskell
import TAD.Conjunto (Conj, vacio, inserta, menor, elimina, pertenece, esVacio) import Data.List (sort, nub) import Test.QuickCheck -- 1ª definición de listaAconjunto -- =============================== listaAconjunto :: Ord a => [a] -> Conj a listaAconjunto [] = vacio listaAconjunto (x:xs) = inserta x (listaAconjunto xs) -- 2ª definición de listaAconjunto -- =============================== listaAconjunto2 :: Ord a => [a] -> Conj a listaAconjunto2 = foldr inserta vacio -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_listaAconjunto :: [Int] -> Bool prop_listaAconjunto xs = listaAconjunto xs == listaAconjunto2 xs -- La comprobación es -- λ> quickCheck prop_listaAconjunto -- +++ OK, passed 100 tests. -- Definición de conjuntoAlista -- ============================ conjuntoAlista :: Ord a => Conj a -> [a] conjuntoAlista c | esVacio c = [] | otherwise = mc : conjuntoAlista rc where mc = menor c rc = elimina mc c -- Comprobación de las propiedades -- =============================== -- La primera propiedad es prop_1_listaAconjunto :: [Int] -> Bool prop_1_listaAconjunto xs = conjuntoAlista (listaAconjunto xs) == sort (nub xs) -- La comprobación es -- λ> quickCheck prop_1_listaAconjunto -- +++ OK, passed 100 tests. -- La segunda propiedad es prop_2_listaAconjunto :: Conj Int -> Bool prop_2_listaAconjunto c = listaAconjunto (conjuntoAlista c) == c -- La comprobación es -- λ> quickCheck prop_2_listaAconjunto -- +++ OK, passed 100 tests.
Soluciones en Python
from __future__ import annotations from abc import abstractmethod from copy import deepcopy from functools import reduce from typing import Protocol, TypeVar from hypothesis import given from hypothesis import strategies as st from src.TAD.conjunto import (Conj, conjuntoAleatorio, elimina, esVacio, inserta, menor, pertenece, vacio) class Comparable(Protocol): @abstractmethod def __lt__(self: A, otro: A) -> bool: pass A = TypeVar('A', bound=Comparable) # 1ª definición de listaAconjunto # =============================== def listaAconjunto(xs: list[A]) -> Conj[A]: if not xs: return vacio() return inserta(xs[0], listaAconjunto(xs[1:])) # 2ª definición de listaAconjunto # =============================== def listaAconjunto2(xs: list[A]) -> Conj[A]: return reduce(lambda ys, y: inserta(y, ys), xs, vacio()) # 3ª solución de listaAconjunto # ============================= def listaAconjunto3(xs: list[A]) -> Conj[A]: c: Conj[A] = Conj() for x in xs: c.inserta(x) return c # Comprobación de equivalencia # ============================ # La propiedad es @given(st.lists(st.integers())) def test_listaAconjunto(xs: list[int]) -> None: r = listaAconjunto(xs) assert listaAconjunto2(xs) == r assert listaAconjunto3(xs) == r # 1ª definición de conjuntoAlista # =============================== def conjuntoAlista(c: Conj[A]) -> list[A]: if esVacio(c): return [] mc = menor(c) rc = elimina(mc, c) return [mc] + conjuntoAlista(rc) # 2ª definición de conjuntoAlista # =============================== def conjuntoAlista2Aux(c: Conj[A]) -> list[A]: if c.esVacio(): return [] mc = c.menor() c.elimina(mc) return [mc] + conjuntoAlista2Aux(c) def conjuntoAlista2(c: Conj[A]) -> list[A]: c1 = deepcopy(c) return conjuntoAlista2Aux(c1) # 3ª definición de conjuntoAlista # =============================== def conjuntoAlista3Aux(c: Conj[A]) -> list[A]: r = [] while not c.esVacio(): mc = c.menor() r.append(mc) c.elimina(mc) return r def conjuntoAlista3(c: Conj[A]) -> list[A]: c1 = deepcopy(c) return conjuntoAlista3Aux(c1) # Comprobación de equivalencia de las definiciones de conjuntoAlista # ============================================================== @given(c=conjuntoAleatorio()) def test_conjuntoAlista(c: Conj[int]) -> None: r = conjuntoAlista(c) assert conjuntoAlista2(c) == r assert conjuntoAlista3(c) == r # Comprobación de las propiedades # =============================== # La primera propiedad es @given(st.lists(st.integers())) def test_1_listaAconjunto(xs: list[int]) -> None: assert conjuntoAlista(listaAconjunto(xs)) == sorted(list(set(xs))) # La segunda propiedad es @given(c=conjuntoAleatorio()) def test_2_listaAconjunto(c: Conj[int]) -> None: assert listaAconjunto(conjuntoAlista(c)) == c # La comprobación de las propiedades es # > poetry run pytest -v TAD_Transformaciones_conjuntos_listas.py # test_listaAconjunto PASSED # test_conjuntoAlista PASSED # test_1_listaAconjunto PASSED # test_2_listaAconjunto PASSED