Seite 1 von 1

Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 16:21
von PyPankow
Hallo zusammen,

ich hoffe, mir kann vielleicht jemand helfen. Ich beschäftige mich gerade mit der Analyse von Strings. Dabei bin auf die sog. Schreibmaschinendistanz gestoßen.
Diese drückt den Abstand von zwei Buchstaben auf der - im dt. QWERTZ-Tastaturbelegung - aus.

Beispielsweise sind die Buchstaben ‚u‘ und ‚i‘ direkt nebeneinander.
Sie haben den Abstand 1. Um vom ‚h‘ zum ‚k‘ zu gelangen, muss man über das ‚j‘ gehen. Der Abstand ist 2.

Hund wäre demnach: H - > U (1); U ->N (2); N->D (4) = Distanz 7.

Ich suche nun ein Snippet, welches die Schreibmaschinendistanz berechnen kann.
Ich bin leider bisher total erfolglos geblieben und suche daher Unterstützung.

Danke Euch!
Gerne auch für weitere Hinweise!

Re: Schreibmaschinendist

Verfasst: Dienstag 28. Dezember 2021, 16:29
von __deets__
Du bist darauf gestoßen? Wozu willst du die denn verwenden? Oder hast du das als Aufgabe bekommen?

Zur Lösung könnte man zb die drei Zeilen der quertz-Belegung als Listen anlegen. Für zwei gegebene Buchstaben ist der Abstand dann die Differenz ihrer Listen Position. Sind die Listen nicht dieselben, muss man dann noch 1 oder 2 addieren, je nach dem in welcher Liste sie stecken.

Re: Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 16:40
von PyPankow
Zum Glück sind die Zeiten mit Aufgaben bekommen vorbei:) Ursprünglich habe ich mich mal mit Dubletten bei einem Verein beschäftigt und bin an dem Thema immer mal wieder hängengeblieben....

Ich verstehe Deinen Ansatz!

Aber wie ist das dann mit ü und ä. Diese sind ja eigentlich nur 1 entfernt. Mit der Listenaddition wären sie doch dann 2 entfernt, oder?

Danke Dir schon mal!

Re: Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 18:27
von __deets__
Die sind so weit entfernt wie du sie in die Listen packst. Letztlich ist dieses Maß ja nicht wirklich sinnvoll beziehungsweise schlecht definiert. Die Tasten sind ja eigentlich versetzt, aber die Distanz reflektiert das ja auch nicht.

Re: Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 18:46
von PyPankow
Ja. Stimmt. Ich dachte, es gibt irgendwo eine Norm dafür. Danke!

Re: Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 19:03
von narpfel
@PyPankow: Es gibt eine Norm dafür: Die Reihen sind jeweils um ¼ Tastenbreite verschoben, bzw. ½ zwischen den Zahlen und der Q-Reihe, ¼ zwischen der Q- und A-Reihe und ½ zwischen A und Y. Weil die Hebel Platz brauchen. ;-)

Re: Schreibmaschinendistanz

Verfasst: Dienstag 28. Dezember 2021, 21:33
von rogerb
Hmm, eigentlich spannend:

Mit networx (leider ohne die tatsächliche Entfernung zu erhalten)

Code: Alles auswählen

from itertools import pairwise
import networkx as nx

WORD = "HUND"

def setup_network():
    top = list("QWERTZUIOPÜ")
    middle = list("ASDFGHJKLÖÄ")
    bottom = list("YXCVBNM")
    keyboard = nx.Graph()
    keyboard.add_nodes_from(top)
    keyboard.add_nodes_from(middle)
    keyboard.add_nodes_from(bottom)
    keyboard.add_edges_from(pairwise(top))
    keyboard.add_edges_from(pairwise(middle))
    keyboard.add_edges_from(pairwise(bottom))
    keyboard.add_edges_from(zip(top, middle))
    keyboard.add_edges_from(zip(top[1:], middle))
    keyboard.add_edges_from(zip(middle, bottom))
    keyboard.add_edges_from(zip(middle[1:], bottom))
    return keyboard


def main():
    keyboard = setup_network()
    paths = [nx.shortest_path(keyboard, previous_letter, next_letter) for previous_letter, next_letter in pairwise(WORD)]
    print(paths)
    
    distances = [len(path) - 1 for path in paths]
    print(distances)

    total_distance = sum(distances)
    print(total_distance)

main()

"""
[['H', 'U'], ['U', 'H', 'N'], ['N', 'B', 'V', 'C', 'D']]
[1, 2, 4]
7
"""
Oder "Bruteforce" wie im Video erwähnt:

Code: Alles auswählen

import math
from itertools import product, pairwise

WORD = "HUND"


def main():
    full_distance = 19.05
    quarter_distance = 19.05 * 0.25
    half_distance = 19.05 * 0.5

    top = {letter: (num * full_distance, 0) for num, letter in enumerate("QWERTZUIOPÜ")}
    middle = {letter: (num * full_distance + quarter_distance, full_distance) for num, letter in enumerate("ASDFGHJKLÖÄ")}
    bottom = {letter: (num * full_distance + quarter_distance + half_distance, 2 * full_distance) for num, letter in enumerate("YXCVBNM")}

    keys = top | middle | bottom

    letter_distances = {(this, other): math.sqrt((tx - ox) ** 2 + (ty - oy) ** 2) for (this, (tx, ty)), (other, (ox, oy)) in product(keys.items(), repeat=2)}
    word_letter_distances = {
        (previous_letter, next_letter): letter_distances[(previous_letter, next_letter)] for previous_letter, next_letter in pairwise(WORD)
    }

    for (this, other), distance in word_letter_distances.items():
        print(f"{this} -> {other}: {distance:0.2f} mm")

    print(f"Total: {sum(word_letter_distances.values()):0.2f} mm")


main()
"""
H -> U: 23.81 mm
U -> N: 38.40 mm
N -> D: 69.34 mm
Total: 131.55 mm
"""

Re: Schreibmaschinendistanz

Verfasst: Mittwoch 29. Dezember 2021, 10:25
von PyPankow
Wow! Herzlichen herzlichen Dank! Sowohl für das Video plus Infos und für den Code! Das macht wirklich Freude! Danke!

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 12:56
von PyPankow
Hallo,

ich habe jetzt das Problem, dass ich pairwise in PyCharm nicht importieren kann. Ich habe bereits nach Alternativen recherchiert, leider alles ohne Erfolg.
Auch hier https://docs.python.org/2/library/itertools.html finde ich nichts dazu. Habt Ihr einen Tipp für mich? Herzlichen Dank!

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 13:15
von Sirius3
PyCharm hat damit nichts zu tun, das ist nur die IDE. Du benutzt eine zu alte Pythonversion. `pairwise` gibt es erst ab Python 3.10.
Die Dokumentation, die Du verlinkt hast, ist für Python2 und das benutzt Du hoffentlich nicht mehr.
https://docs.python.org/3/library/itert ... s.pairwise

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 15:33
von __blackjack__
Ansonsten gibt es `pairwise()` für Python <3.10 auch im externen `more_itertools`-Modul.

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 16:00
von PyPankow
Ach, manchmal! Tausend Dank!

Ich habe jetzt Python aktualisiert und über more_itertools pairwise importiert. Das klappt!

Ich knobel jetzt noch an der letzten Fehlermeldung, die ich in myCharm bekomme, wenn ich die Printbefehle nach def ergänze....

print(f"Total: {sum(word_letter_distances.values()):0.2f} mm")
print("Hier endet der Code")

Fehlermeldung:

n <module>
print(f"Total: {sum(word_letter_distances.values()):0.2f} mm")
NameError: name 'word_letter_distances' is not defined

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 16:03
von sparrow
Die Fehlermeldung sagt, dass kein Wert an den Namen gebunden wurde.
Mehr kann man nicht sagen, wenn du den Code nicht zeigst, der den Fehler verursacht.

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 16:36
von PyPankow
Danke! Das ist im Grunde der Code von oben, angepasst beim Import und eben die zwei Print-Befehle
Ohne die vorletzte Zeile gibt es keinen Fehler, aber auch kein Ergebnis......

Code: Alles auswählen

#from itertools import pairwise
from itertools import product
from more_itertools import pairwise
import math


WORD = "HUND"


def main():
    full_distance = 19.05
    quarter_distance = 19.05 * 0.25
    half_distance = 19.05 * 0.5

    top = {letter: (num * full_distance, 0) for num, letter in enumerate("QWERTZUIOPÜ")}
    middle = {letter: (num * full_distance + quarter_distance, full_distance) for num, letter in enumerate("ASDFGHJKLÖÄ")}
    bottom = {letter: (num * full_distance + quarter_distance + half_distance, 2 * full_distance) for num, letter in enumerate("YXCVBNM")}

    keys = top | middle | bottom

    letter_distances = {(this, other): math.sqrt((tx - ox) ** 2 + (ty - oy) ** 2) for (this, (tx, ty)), (other, (ox, oy)) in product(keys.items(), repeat=2)}
    word_letter_distances = {
        (previous_letter, next_letter): letter_distances[(previous_letter, next_letter)] for previous_letter, next_letter in pairwise(WORD)
    }

    for (this, other), distance in word_letter_distances.items():
        print(f"{this} -> {other}: {distance:0.2f} mm")

    print(f"Total: {sum(word_letter_distances.values()):0.2f} mm")


print(f"Total: {sum(word_letter_distances.values()):0.2f} mm")
print("Hier endet der Code")

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 16:44
von sparrow
Weil es auf Modulebene kein "word_letter_distances" gibt. Und das ist auch richtig so.
Wenn das dein ganzes Script ist, wo genau rufst du da die Funktion main() auf?
In der Regel sieht der Eintiegspunkt dafür am Ende des Scripts so aus:

Code: Alles auswählen

if __name__ == "__main__":
    main()
Auf Modulebene (also ohne Einrückung) stehen nur Importe, die Definition von Konstanten, Klassen und Funktionen und eben am Ende des Scripts dieser Zweizeiler um die Funktion main aufzurufen.

Re: Schreibmaschinendistanz

Verfasst: Dienstag 11. Januar 2022, 16:45
von __blackjack__
@PyPankow: `word_letter_distances` ist *in* der Funktion definiert. Du versuchst ausserhalb der Funktion darauf zuzugreifen wo es halt undefiniert ist. Und in der Funktion steht diese Zeile doch bereits‽

Was bei dem Code fehlt ist der Aufruf der `main()`-Funktion. Wenn man Funktionen nicht aufruft, dann passiert auch nix. Also am Ende statt der `print()`-Zeilen:

Code: Alles auswählen

if __name__ == "__main__":
    main()

Re: Schreibmaschinendistanz

Verfasst: Donnerstag 13. Januar 2022, 13:56
von PyPankow
Erneut ein Danke! Ich habe jetzt getüftelt und in myCharm die Main Funktion eingebaut. Sie greift auch auf das Modul/Funktion distanz zu.

Der Code dafür sieht so aus. Ja.. Einstiegsniveau... :)

Code: Alles auswählen

import distanz

if __name__ == "__main__":
   distanz.WORD
   print(distanz.WORD)
   print(distanz.pairwise("fgdgf"))
   print(distanz.distanz())
Die Fehlermeldung hat sich sich jetzt verändert und meldet nicht unterstützte Operatoren. Da bin ich ehrlich gesagt überfragt. Frage mich, warum der Fehler bei mir kommt. Stichwort Versionen oder fehlt eine lib oder oder oder.... Die Operatoren müssten doch unterstützt werden...

Code: Alles auswählen

line 20, in distanz
    keys = top | middle | bottom
TypeError: unsupported operand type(s) for |: 'dict' and 'dict'

Re: Schreibmaschinendistanz

Verfasst: Donnerstag 13. Januar 2022, 14:05
von __deets__
noe, der |-Operator ist zumindest auch bei mir fuer dicts nicht unterstuetzt. Ich habe Python 3.8. Kann sein, dass neuere Pythons den unterstuetzen. Den kanst du dir aber auch trivial nachbauen, durch ein leeres dict und zwei update calls. Das ist ja nur Kombination aus allen Eintraegen.

Re: Schreibmaschinendistanz

Verfasst: Donnerstag 13. Januar 2022, 14:49
von Sirius3

Re: Schreibmaschinendistanz

Verfasst: Samstag 15. Januar 2022, 16:14
von PyPankow
Vielen vielen Dank! Jetzt funktioniert es! Super!!!