Analyse: Smiley-Jagd 🕵️‍♂️

Schauen wir uns die eingereichte Lösung an:

import re

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


Funktioniert es? Ja. Würde man das in Produktion lassen? Nein.

1️⃣ Sünde der Allokation
Eckige Klammern innerhalb von sum([ ... ]) bedeuten, dass Python zuerst eine vollständige Liste aus True/False in der Größe des ursprünglichen Arrays im Speicher erstellt und erst dann summiert. Wenn ein Log mit 10 Millionen Zeilen eingeht, ist der Speicher weg.
Entfernen wir die Klammern – wir erhalten einen Generatorausdruck. Speicher O(1) statt O(n).

2️⃣ Überflüssige Prüfungen
Die Konstruktion match(...) is not None ist zwar gültig, aber in Python verwendet man die eingebaute „Wahrhaftigkeit“ (truthiness) von Objekten. Außerdem wollen wir nur die Anzahl der Übereinstimmungen zählen. Idiomatischer Ansatz: sum(1 for ... if ...)

3️⃣ Neukompilierung
Der Aufruf von re.match innerhalb der Schleife zwingt Python jedes Mal, in den Regex-Cache zu gehen. Bei vielen Zeilen sollte das Muster einmal vor der Schleife kompiliert werden.

Werfen wir den Müll weg und schreiben so:
import re

# Kompilierung nach oben auslagern
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))


☝️Aber das Hauptproblem dieser Lösung ist nicht die Syntax.
Warum brauchen wir hier überhaupt reguläre Ausdrücke?

Rechnen wir: Wir haben 2 Augenoptionen, 3 Nasenoptionen (einschließlich keiner Nase) und 2 Mundoptionen.
Es gibt genau 12 gültige Smileys. Wie @archimage_wiz schrieb, reicht es, statt für jede Zeile die schwere Zustandsmaschine regulärer Ausdrücke zu starten, die Zugehörigkeit zu einer vorbereiteten Menge (set) zu prüfen.

Die Suche in einer Menge erfolgt in konstanter Zeit O(1) (es ist eine Hashtabelle).

Lösung eines gesunden Menschen:
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)


Dieser Code benötigt kein Importieren des Moduls re, er ist für jeden Junior auf den ersten Blick offensichtlich und bei großen Datenmengen wird er reguläre Ausdrücke in der Ausführungsgeschwindigkeit vernichten.

Komplexe Werkzeuge sind cool. Aber die Fähigkeit, mit einfachen auszukommen, ist eine Fertigkeit.

#algogespräch