Análisis: Caza de emoticonos 🕵️‍♂️

Veamos la solución enviada:

import re

def num_emojis(arg):
return sum([re.match("^[:;][~-]?[)D]$",i) is not None for i in arg])


¿Funciona? Sí. ¿Dejarías eso en producción? No.

1️⃣ Pecado de asignación
Los corchetes dentro de sum([ ... ]) significan que Python primero creará en memoria una lista completa de True/False del tamaño del array original, y solo luego la sumará. Si la entrada es un log de 10 millones de líneas, tu memoria se va al carajo.
Quitamos los corchetes y obtenemos una expresión generadora. Memoria O(1) en lugar de O(n).

2️⃣ Comprobaciones redundantes
La construcción match(...) is not None tiene derecho a existir, pero en Python se usa la "veracidad" (truthiness) de los objetos. Además, solo necesitamos contar el número de coincidencias. Enfoque idiomático: sum(1 for ... if ...)

3️⃣ Recompilación
Llamar a re.match dentro del bucle cada vez obliga a Python a acceder al caché de expresiones regulares. Si hay muchas cadenas, el patrón debe compilarse una vez antes del bucle.

Tiramos la basura y escribimos así:
import re

# Sacamos la compilación arriba
SMILEY_PATTERN = re.compile(r"^[:;][~-]?[)D]$")

def count_smileys(faces: list[str]) -> int:
return sum(1 for face in faces if SMILEY_PATTERN.match(face))


☝️Pero el principal problema de esta solución no es la sintaxis.
¿Para qué necesitamos expresiones regulares aquí?

Contemos: tenemos 2 opciones de ojos, 3 opciones de nariz (incluyendo su ausencia) y 2 opciones de boca.
Exactamente 12 emoticonos válidos. Como escribió @archimage_wiz, en lugar de ejecutar una pesada máquina de estados de expresiones regulares en cada línea, basta con verificar si la cadena está en un conjunto (set) predefinido.

La búsqueda en un conjunto es de tiempo constante O(1) (es una tabla hash).

Solución de una persona sensata:
from typing import List

VALID_SMILES = {
':)', ';)', ':-)', ';-)', ':~)', ';~)',
':D', ';D', ':-D', ';-D', ':~D', ';~D'
}

def num_emojis_pro(arr: List[str]) -> int:
return sum(s in VALID_SMILES for s in arr)


Este código no requiere importar el módulo re, es obvio para cualquier junior a primera vista, y en grandes volúmenes de datos destruirá a las expresiones regulares en velocidad de ejecución.

Las herramientas complejas son geniales. Pero saber arreglárselas con las simples ya es una habilidad.

#algosobes