Examen MP Datos Resuelto Mayo 2022

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 5

Apellidos:

Nombre: D.N.I.:

Introducción a la Programación - E.P. de Ingeniería de Gijón


18 de mayo de 2023

1. (1 p) Indica si las siguientes afirmaciones son verdaderas o falsas:


¿Es verdad?
Python Jene un operador ternario (tres argumentos) ⊠Si □No
Si type(x) == tuple entonces x[0] = 10 establece el valor 10 como primer elemento □Si ⊠No
Si type(x) == list entonces x[0] = 10 establece el valor 10 como primer elemento ⊠Si □No
Si type(x) == set entonces x[0] = 10 establece el valor 10 como primer elemento □Si ⊠No
Se pueden anidar bucles de disJntos Jpos (ej. un while dentro de un for, o viceversa) ⊠Si □No
El cuerpo de un bucle for siempre se ejecuta al menos una vez □Si ⊠No
Un atributo de una clase/objeto es privado si su nombre comienza por dos asteriscos □Si ⊠No
No se puede iterar sobre los elementos de un diccionario con un for □Si ⊠No
Sólo el primer parámetro de una función puede tomar valor por defecto □Si ⊠No
La expresión {1: 2, 3: 4} denota un conjunto (set) de cuatro elementos en Python □Si ⊠No

2. (2 p) Las porciones de código siguientes, ¿hacen lo que pide el enunciado? En caso nega.vo, explica por qué:
Acumula en s la suma de los n prime- Imprime m×n veces el mensaje (con Asigna a r el cuadrado de x, pero sólo
ros números impares posiJvos: m>0 y n>0): si x>=0:
s: int = 0 for i in range(1, m): r: int = 0
for i in range(1, n + 1, 2): for j in range(1, n): i: int = 1
s += i print("mensaje") while i <= x:
r += x
i += 1
□Si ⊠No □Si ⊠No ⊠Si □No
Solucion: El valor de s será la suma Solucion: El mensaje se imprimi-
de los impares en el intervalo [1, n], rá (m-1)×(n-1) veces, ya que
que no es lo mismo que la suma de range(x, y) itera desde x hasta
los n primeros impares. y-1

3. (3 p) Escribe en Python la función serie_extraña(), que retorna el valor de la serie SL , uJlizando sus n primeros
términos, siendo n el único parámetro que se pasa a la función:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
SL = + − − + + + − − − − + + + + + − − − ...
1 2 3
󰁿󰁾󰁽󰂀 󰁿 󰁾󰁽 󰂀 󰁿 4 5
󰁾󰁽 6
󰂀󰁿 7 8 󰁾󰁽 9 10󰂀󰁿 11 12 13
󰁾󰁽 14 15
󰂀󰁿 16 17
󰁾󰁽 󰂀
1 pos. 2 neg. 3 pos. 4 neg. 5 pos. 6 neg.

Solución: def serie_extraña(n: int) -> float:


suma: float = 0
signo: float = +1
contador_mismo_signo: int = 0
cuantos_del_mismo_signo: int = 1
for i in range(1, n + 1):
suma += signo / i
contador_mismo_signo += 1
if contador_mismo_signo == cuantos_del_mismo_signo:
signo = -signo
cuantos_del_mismo_signo += 1
contador_mismo_signo = 0

return suma

Pág. 1 de 5
4. (2 p) Escribe las condiciones para que el condicional imprima el mensaje cuando deba hacerlo:
(a) Suponiendo que M es un tensor NumPy:

if M.ndim == 3 o también len(M.shape) == 3 :


print("M es un tensor tridimensional")

(b) Suponiendo tres variables numéricas, a, b y c:

if a > c >= b o también a > c and c >= b :


print("El valor de a es el mayor de todos, y el valor de b no supera el de c")

(c) Suponiendo que b1 y b2 son variables booleanas:

if not (b1 or b2) o también not b1 and not b2 :


print("No es verdad b1 ni tampoco b2, ambas son falsas")

(d) Suponiendo una cadena de caracteres msg:

if len(msg) % 2 != 0 :
print("La frase msg tiene un número impar de caracteres")

5. (3 p) Rellena el código que falta en el siguiente programa para que los números contenidos en la lista l se distribuyan
en 5 conjuntos diferentes: uno que contenga los números menores o iguales a 3, otro con los mayores que 3 y menores
o iguales que 6, y otro con los mayores que 6. Además, los números de este úlJmo conjunto también se distribuyen en
otros dos conjuntos, los que son pares y los que son impares. La parte final del código que se entrega produce la salida
que puedes ver más abajo.
l: list = [1, 7, 2, 9, 3, 5, 4, 5, 6, 6, 6, 8, 9, 10]

Solución:

# Declaramos e inicializamos los conjuntos vacíos necesarios


pequeños: set = set()
medianos: set = set()
grandes: set = set()
grandes_pares: set = set()
grandes_impares: set = set()
# Recorremos la lista y repartimos su contenido en los conjuntos
# se puede utilizar cjto |= {elemento} o bien cjto.add(elemento)
for elemento in l:
if elemento <= 3:
pequeños.add(elemento)
elif elemento <= 6:
medianos |= {elemento}
else:
grandes |= {elemento}
if elemento % 2 == 0:
grandes_pares.add(elemento)
else:
grandes_impares.add(elemento)

print(f"Lista original: {l}")


nombres: tuple = ("Peq.", "Med.", "Gra.", "Gra.(p)", "Gra.(i)")
cjtos: tuple = (pequeños, medianos, grandes, grandes_pares, grandes_impares)
for i in range(len(nombres)):
print(nombres[i], cjtos[i], sep="\t")

Lista original: [1, 7, 2, 9, 3, 5, 4, 5, 6, 6, 6, 8, 9, 10]


Peq. 1, 2, 3
Med. 4, 5, 6
Gra. 8, 9, 10, 7
Gra.(p) 8, 10
Gra.(i) 9, 7

Pág. 2 de 5
6. (4 p) Implementa de forma eficiente la función buscar_sublista(), que recibe como parámetros una lista de números,
lista, y un número adicional, suma. La función debe retornar una tupla con dos índices, que determinen una sublista
cuya suma coincida con suma. Si no hay tal sublista se retornará una tupla vacía. Algunos ejemplos:
Siendo x = [1, 9, 1, 1, 1, 2, 2, 3, 7]:
buscar_sublista(x, 6) -> (3, 7) ya que x[3] + x[4] + x[5] + x[6] = 1 + 1 + 2 + 2 = 6
buscar_sublista(x, 9) -> (1, 2) ya que x[1] = 9 = 9
buscar_sublista(x, 10) -> (0, 2) ya que x[0] + x[1] = 1 + 9 = 10
buscar_sublista(x, 100) -> () ya que no hay sublistas que sumen 100
Nota: recuerda que puedes calcular la suma de una sublista pasándosela como argumento a sum().
i j
Secuencia: (0, 1), (0, 2), (0, 3), . . . (1, 2), (1, 3), (1, 4) . . .
Solución: Primer elemento: (i, j) = (0,
󰀝 1)
(i, j + 1), si sum(lista[i : j]) < suma
Siguiente elemento: (i, j) =
(i + 1, i + 2), en otro caso
Fin de secuencia: i >= len(lista)oj > len(lista)
Elemento encontrado: sum(lista[i : j]) == suma

def buscar_sublista(lista: list, suma: int) -> tuple:


# Obtener primer elemento
i: int = 0
j: int = 1
# Mientras NO fin secuencia y NO elemento encontrado
while i < len(lista) and j <= len(lista) and sum(lista[i:j]) != suma:
# Obtener siguiente elemento:
if sum(lista[i:j]) < suma:
# si la suma es menor y puedo ampliar la sublista, la amplio
j += 1 # equivalente a i, j = i, j + 1
else:
# y si no, desplazo el comienzo y empezamos de nuevo
i, j = i + 1, i + 2
# Si NO fin secuencia,
if i < len(lista) and j <= len(lista):
return (i, j) # hemos encontrado la sublista
else:
return () # no hemos encontrado la sublista

7. (3 p) Implementa la función zigzag(), que recibe como parámetro un ndarray bidimensional (matriz) y retorna un
ndarray unidimensional (vector) con el contenido de la matriz extraído de ésta mediante recorrido en zig-zag como se
muestra en el ejemplo siguiente:
1 2 3 4
m= 5 6 7 8✻ −→ zigzag(m) retornará 1 5 9 10 6 2 3 7 11 12 8 4
9 10 11 12

Nota: Recuerda que el atributo shape de los objetos ndarray es una tupla con el tamaño en cada dimensión, y que se pueden crear
un ndarray vacío con np.empty(t), siendo t un número entero o una tupla de enteros con las dimensiones del nuevo array.

Solución: Suponiendo que el código comienza con import numpy as np, podríamos hacer:
Versión 1 Versión 2
def zigzag_columnas(matriz: np.ndarray) -> np.ndarray: def zigzag_columnas(matriz: np.ndarray) -> np.ndarray:
filas, columnas = matriz.shape filas, columnas = matriz.shape
# creamos un vector con el tamaño adecuado # creamos un vector con el tamaño adecuado
vector: np.ndarray = np.empty(filas * columnas) vector: np.ndarray = np.empty(filas * columnas)
k: int = 0 k: int = 0
for c in range(columnas): for c in range(columnas):
if c % 2 == 0: if c % 2 == 0:
for f in range(filas): vector[k : k + filas] = matriz[:, c]
vector[k] = matriz[f, c] else:
k += 1 vector[k : k + filas] = matriz[::-1, c]
else: k += filas
for f in range(filas - 1, -1, -1): return vector
vector[k] = matriz[f, c]
k += 1
return vector

Pág. 3 de 5
8. (4 p) Implementa la clase BOW (bag of words), cuyos objetos permiten contar el número de apariciones de palabras en
un texto, entendiendo por palabra el conjunto de caracteres entre espacios en blanco. Los detalles de implementación
son los siguientes:

⊲ Atributos:
◦ Un atributo de Jpo dict, en el que cada clave será una palabra del texto y su dato asociado será un valor entero
indicando cuántas veces se ha contabilizado esa palabra. Este atributo no es accesible desde el exterior de la clase,
ni siquiera para lectura.
◦ Un atributo de Jpo str, que especifica los caracteres que se descartarán en el procesado de los textos1 . No se
podrá modificar una vez construido el objeto, pero sí se podrá consultar.
⊲ Propiedades:
◦ eliminables: sirve para consultar el valor es la cadena de símbolos que se descartan al procesar los textos. Re-
cuerda que no se puede modificar dicha cadena, sólo se puede leer.
◦ núm_palabras, cuyo valor es un número entero indicando cuántas palabras diferentes aparecen en el texto con el
que se creó la bolsa.
◦ núm_total_ocurrencias, cuyo valor es un número entero indicando cuantas palabras (incluyendo repeJciones)
se procesaron en el texto con el que se creó la bolsa.
◦ palabras: cuando se consulta esta propiedad se obJene una cadena de texto con todas las palabras contenidas en
el objeto, separadas por espacio en blanco (generalmente no coincidirá con el texto original, ver ejemplo, línea 9).
Cuando se asigna una cadena de texto a esta propiedad, se vuelve a calcular de nuevo el contenido del diccionario
que lleva el conteo (ver ejemplo más abajo, líneas 5 y 10).
⊲ Métodos:
◦ El método “constructor”, que lleva dos parámetros opcionales: el texto a procesar (su valor por defecto será "") y
la cadena de caracteres eliminables antes del conteo de palabras (su valor por defecto será ".,;-¿?").
◦ El método num_ocurrencias(), que lleva como parámetro obligatorio una palabra y retorna el número de ocu-
rrencias de dicha palabra en la bolsa.
◦ El método “mágico” que permite sumar bolsas de palabras, retornando un nuevo objeto BOW con la bolsa de palabras
resultante de fusionar ambas bolsas (ver ejemplo más abajo). Para poder sumar dos bolsas de palabras, ambas
deben tener el mismo conjunto de símbolos eliminables, que será el que también tenga la bolsa resultante. Si esto
no es así, la operación provocará una excepción con raise ValueError.
◦ El método “mágico” que retorna una cadena representando el contenido de la bolsa, tal como se ve en la salida de
las instrucciones print del ejemplo que se muestra a conJnuación.
Bolsa b1:
6 palabras (4 únicas)
Esto ( 1) *
1 b1: BOW = BOW(texto="Esto es texto, ¿es poco texto?") es ( 2) **
2 print("Bolsa b1:") texto ( 2) **
3 print(b1) poco ( 1) *
4 b2: BOW = BOW()
Bolsa b3:
5 b2.palabras = "Esto es otro texto."
8 palabras (5 únicas)
6 b3: BOW = b1 + b2 Esto ( 2) **
7 print("Bolsa b3:") =⇒ es ( 2) **
8 print(b3) texto ( 2) **
9 print(f"Palabras en b1: '{b1.palabras}'") poco ( 1) *
10 b1.palabras = "-Otro texto-" otro ( 1) *
11 print("\nb1 ha cambiado:")
Palabras en b1: 'Esto es texto poco'
12 print(b1)
b1 ha cambiado:
2 palabras (2 únicas)
Otro ( 1) *
texto ( 1) *

Te puede resultar úJl recordar cómo funcionan los métodos split() y join(). Observa los siguientes ejemplos:

⊲ "de cadena a lista".split() ⇝ ["de", "cadena", "a", "lista"]


⊲ " ".join(["de", "lista", "a", "cadena"]) ⇝ "de lista a cadena"
⊲ "".join(["p","a","l","o"]) ⇝ "palo"

1 Por ejemplo, si este atributo toma el valor "-." y se suministra el texto "sub-índice menor.", en realidad se va a hacer el conteo de palabras del

texto "subíndice menor".

Pág. 4 de 5
Solución:
from __future__ import annotations

class BOW:
def __init__(self, texto: str = "", eliminables: str = ".,;-¿?") -> None:
# Atributos
self.__eliminables: str = eliminables
self.__palabras: dict = {}
# rellenamos el atributo usando el setter, para el procesamiento
# del texto suministrado
self.palabras = texto

@property
def eliminables(self) -> str:
return self.__eliminables

@property
def palabras(self) -> str:
return " ".join(list(self.__palabras))

@palabras.setter
def palabras(self, texto: str) -> None:
lista_caracteres: list = [c for c in texto if c not in self.__eliminables]
texto_aux: str = "".join(lista_caracteres)
# texto_aux es el resultado de quitar los caracteres eliminables a texto
lista_palabras: list = texto_aux.split()
# vaciamos el diccionario, por si hubiese datos
self.__palabras = {}
for p in lista_palabras:
self.__palabras[p] = self.núm_ocurrencias(p) + 1

@property
def núm_total_ocurrencias(self) -> int:
# return sum(list(self.__palabras.values()))
total: int = 0
for p in self.__palabras:
total += self.__palabras[p]
return total

@property
def núm_palabras(self) -> int:
return len(self.__palabras)

def núm_ocurrencias(self, p: str) -> int:


# return self.__palabras.get(p, 0)
return self.__palabras[p] if p in self.__palabras else 0

def __add__(self, b: BOW) -> BOW:


# los eliminables pueden estar en distinto orden pero ser iguales
if set(self.eliminables) != set(b.eliminables):
raise ValueError("Símbolos eliminables incompatibles")
return BOW(self.palabras + " " + b.palabras, self.eliminables)

def __str__(self) -> str:


texto: str = ""
texto += f"{self.núm_total_ocurrencias} palabras"
texto += f" ({self.núm_palabras} únicas)\n"
for p, n in self.__palabras.items():
texto += f"{p:15} ({n:3}) " + "*" * n
texto += "\n"

return texto

Pág. 5 de 5

También podría gustarte