Samstag, 2. März 2013

CSI Crime Lab

Bei Aufgabe „CSI Crime Lab“ von HP Codewars VII sollte eine DNA-Prüfung implementiert werden, was mich etwas Zeit und Energie gekostet hat, weniger aufgrund der Komplexität der Aufgabe, als vielmehr, weil ich mir die Datenstruktur mit 2 dictionaries und dort u. U. hinterlegten Listen erst einmal vorgestellen musste.
# CodeWars VII Problems
# CSI Crime Lab

def suspects_aufbereiten(suspects):
    ''' Soll die Daten aufbereiten und in
    ein Wörterbuch packen
    '''
    personen = {}

    suspects = suspects.split("\n")
    for suspect in suspects:
        name,DNA = suspect.split(": ")
        personen[name] = DNA
    return personen


def daten_aufbereiten(scene):
    ''' Soll die Daten vom Tatort
    aufbereiten
    '''
    data = {}
    
    scene = scene.split("\n")
    for datum in scene:
        datum = datum.replace("On ","")
        ort,dna_spur = datum.split(": ")
        data[ort] = dna_spur.split(", ") # Werte sind in einer Liste (!)
    return data


def spuren_prüfen(suspects,spuren):
    ''' Vorgaben von HP
    a.) Es gibt nur einen Verdächtigen, dessen Name
        zurückgegeben werden muss
    b.) Falls kein positiver Treffer, dann ist die Ausgabe
        des Programms "NO MATCH", berücksichtigen
    c.) Positiver Treffer nur, wenn ein Verdächtiger
        DNA-Spuren an allen Tatorten hinterlassen hat
    d.) Es kann je Tatort mehrere DNA-Spuren geben

    Achtung - meine Ergänzung
    e.) Das Programm liefert nur den ersten Treffer mit
        Spuren an allen Tatorten zurück. Es wird nicht
        geprüft, ob das auch für andere Verdächtige
        zutrifft. Das könnte eine Fehlerquelle sein!
    '''

    # Beispieldaten
    # Larry King: GACTAATAACTTCATATATACACAGGTTAC
    # revolver: GACTATTC, GACTAATA

    # Was muss getan werden?
    # Prüfe, ob eine der Spuren in der DNA-Sequenz enthalten ist

    results = {}
    
    for suspect in suspects:

        results[suspect] = 0
        
        dna = suspects[suspect]

        for spurensatz in spuren:   # Spuren im Datensatz

            match = False

            for spur in spuren[spurensatz]:

                if spur in dna:
                    match = True

            if match == True:
                results[suspect] += 1
    
    # Rückgabe: Name eines Verdächtigen oder "" (= False!)
    keys = results.keys()
    for key in keys:
        if results[key] == 3:
            return key
    else:
        return "NO MATCH"


suspects = """Larry King: GACTAATAACTTCATATATACACAGGTTAC
Paula Abdul: GACTATTCATCATAGATAGACAGTACCTAA
Charlie McCarthy: GATTCATTGACATACATACATTAGAGTTCA"""

scene = """On revolver: GACTATTC, GACTAATA
On door: GACTAAT, CATAGAT
On phone: CATACATT, ATTAGAG, ATAGATAG"""

# Daten aufbereiten
suspects = suspects_aufbereiten(suspects)

spuren = daten_aufbereiten(scene)

# Schick die Daten durch die Datenbank
suspect = spuren_prüfen(suspects,spuren)

# Ermittle das Ergebnis
if not suspect == "NO MATCH":
    print("The suspect is: {}".format(suspect))
else:
    print("NO MATCH")
Das hätte wohl etwas den Zeitrahmen gesprengt und ich bin mir auch noch nicht sicher, ob das wirklich die beste Implementierung ist. Produktiv würde ich das jedenfalls nicht zum Einsatz empfehlen, weil nur ein erster Verdächtiger benannt wird, nicht alle möglichen Täter ermittelt werden.

1 Kommentar:

  1. Für beide Datenbereiche sind Wörterbücher nicht wirklich erforderlich, weil ja nie über den Schlüssel auf die Daten zugegriffen werden muss, denn es werden *immer* nur alle Schlüssel/Wert-Paare nacheinander abgearbeitet. Da hätten es Listen mit Tupeln die diese Paare enthalten auch getan.

    Es werden für meinen Geschmack zu viele Zwischenergebnisse an Namen gebunden. Statt ``x = x.split('\n')`` und dann ``for y in x:`` hätte man auch gleich ``for y in x.split('\n'):`` schreiben können.

    Die gesamte `suspects_aufbereiten()` könnte aus einer einzigen Zeile bestehen: ``return dict(suspect.split(': ') for suspect in suspects.split('\n'))``. Oder wie weiter oben schon erwähnt: ``return [tuple(suspect.split(': ')) for suspect in suspects.split('\n')]``.

    Das `replace()` von "On " ist eventuell gefährlich, weil nicht garantiert ist, dass dieses Buchstabensequenz nicht noch einmal in der Zeile auftaucht. Zum Beispiel wenn es am Tatort, einem Radiostudio, ein Schild mit der Aufschrift "On Air" mit Spuren gab. Letztendlich braucht man die Bescchreibung von der DNA-Liste aber auch *überhaupt nicht* zum Lösen der Aufgabe!

    `spuren_prüfen()` liesse sich mit `any()` und `all()` vereinfachen.

    Der Kommentar vor der Rückgabe passt nicht zum Quelltext. Es wird nicht "" zurückgegegen sondern "NO MATCH".

    Die Funktion ist ausserdem fehlerhaft, weil sie beim Vergleich am Ende fest von *drei* Gegenständen ausgeht, was aber nicht garantiert ist so wie ich die Aufgabe verstehe.

    AntwortenLöschen