# Aux pre examen

########################################   P1   #############################################
class Relacion:

    #Inicializador de Relacion
    def __init__(self):
        self.lista = []

    #agregarPar self int int -> None
    # Agrega el par (x,y) solo si no estaba previamente
    # Printea Se agregó el par (x,y) a la lista si se pudo agregar,
    # Si no printea El par (x,y) ya estaba en la lista
    def agregarPar(self,x,y):
        #Revisamos que el par no esté en la lista
        if (x,y) not in self.lista:
            #Si es que no estaba, la agregamos e imprimimos mensaje
            self.lista.append((x,y))
            print(f"Se agregó el par ({x},{y}) a la lista")
        else:
            #Si es que estaba, imprimimos mensaje
            print(f"El par ({x},{y}) ya estaba en la lista")
        

    #ordenadas self int -> lista
    #Devuelve una lista con todas las tuplas que tengan a
    #x como primer valor
    def ordenadas(self,x):
        #Creamos una lista auxiliar
        lista_aux = []
        #Iteramos sobre todos los elementos de la lista de la relacion
        for par in self.lista:
            #Revisamos si el primer elemento de la tupla es igual a x
            if par[0] == x:
                #En el caso de que lo sea, la agregamos a nuestra lista aux
                lista_aux.append(par)
        #Despues de iterar por toda la lista, se retorna la lista aux
        return lista_aux

    #ordenadas self int -> lista
    #Devuelve una lista con todas las tuplas que tengan a
    #y como segundo valor
    def abcisas(self,y):
        #Creamos una lista auxiliar
        lista_aux = []
        #Iteramos sobre todos los elementos de la lista de la relacion
        for par in self.lista:
            #Revisamos si el segundo elemento de la tupla es igual a y
            if par[1] == y:
                #En el caso de que lo sea, la agregamos a nuestra lista aux
                lista_aux.append(par)
        #Despues de iterar por toda la lista, se retorna la lista aux
        return lista_aux

#Probamos el uso:
a = Relacion()
a.agregarPar(2,3)
a.agregarPar(2,3)
a.agregarPar(4,3)
a.agregarPar(4,8)
print(a.ordenadas(4))
print(a.abcisas(3))

#######################################   P2    ######################################

#Programa:

#Abrimos el archivo en modo lectura
a = open("P2.txt","r")
#Leemos la primera linea
linea = a.readline()
#Lista Auxiliar, le agregamos la primera palabra
palabras_ordenadas = [linea]
#Leemos la segunda línea
linea = a.readline()
#Hacemos un ciclo while leer todas las líneas
while linea!= "":
    #sacamos el largo de la palabra
    largo = len(linea)
    #Iteramos sobre nuestra lista aux
    for i in range(len(palabras_ordenadas)):
        #Si la linea actual es una palabra que su largo
        #es menor a la i-esima palabra que estoy comparando
        if len(palabras_ordenadas[i]) >= largo:
            #La interto en la i-esima posicion
            palabras_ordenadas.insert(i,linea)
            #Si la agregué, debo cortar el for
            break
    #Caso en el que nunca agregué la palabra
    if linea not in palabras_ordenadas:
        #La inserto al final de la lista
        palabras_ordenadas.append(linea)
    #Actualizo la linea
    linea = a.readline()

#Cuando salimos del while, leimos todas las palabras y ya están ordenadas
#en palabras_ordenadas
#Cerramos el archivo
a.close()


#Creamos el archivo en modo escritura
b = open("respuesta.txt","w")
#Iteramos en la lista de palabras ordenadas segun largo
for palabra in palabras_ordenadas:
    #Si es que la palabra que vamos a escribir, no tenia
    #el salto de linea, se lo agregamos
    if "\n" not in palabra:
        palabra = palabra + "\n"
    #Escribimos la palabra en el archivo
    b.write(palabra)
#Cuando salimos del for, ya escribimos todas las palabras
#Cerramos el archivo
b.close()

#######################################     P3    ####################################

#Importamos
from lista import *

#merge: lista, lista -> lista
#recibe dos listas enlazadas a y b ordenadas de manera decreciente,
#y retorna una nueva lista enlazada ordenada que contiene los elementos
#de a y b de forma creciente
def merge(a, b):
    # Caso base: si una de las listas es vacía, devuelve la otra lista
    if a == listaVacia:
        return b
    elif b == listaVacia:
        return a

    # Obtiene las cabezas de ambas listas
    Ca = cabeza(a)
    Cb = cabeza(b)

    # Compara las cabezas y llama recursivamente a merge con la cola correspondiente
    if Ca > Cb:
        return lista(Ca, merge(cola(a), b))
    else:
        return lista(Cb, merge(a, cola(b)))

a = crearLista(6,crearLista(5,crearLista(3,crearLista(1, None))))
b = crearLista(15, crearLista(10,crearLista(8,crearLista(4,crearLista(2, crearLista(0,None))))))
c = merge(a,b)
print(c)

##########################################  P4  ##############################################
#selection_sort: lista -> lista
#Devuelve la lista ordenada mediante el algoritmo selection Sort
def selection_sort(a):
    #Obtenemos el largo de la lista
    l = len(a)
    #Iteramos por toda la lista
    for i in range(l):
        #Asumimos que el indice menor es el primero
        min_index = i
        #Iteramos desde i hasta el final de la lista
        for j in range(i,l):
            #Revisamos si el valor del indice j es menor al minimo
            if a[j]<a[min_index]:
                #Actualizamos al indice del valor minimo
                min_index = j
        #Cambiamos el i-esimo valor con el indice del valor mínimo
        a[i],a[min_index] = a[min_index],a[i]
    #Fuera de ambos for ya se ordenó la lista
    #Retornamos la lista actualizada
    return a

























    
