Alle doppelten Wörter aus einem Readlines Array entfernen, ohne eingebaute Funktionen zu verwenden

Code-Stücke können hier veröffentlicht werden.
Antworten
Melthe
User
Beiträge: 9
Registriert: Dienstag 8. Januar 2019, 17:33

Hey Hey,
ich sitze jetzt schon seit fast 3 Tagen an einer Aufgabe, die ich mir selber gestellt habe, in Hinsicht meine Klausur zu bestehen.
Nehmen wir an, wir haben ein readlines Array a=["Hallo, na du wie gehts\n","Hallo na\n", "na wie Wochenende\n"] und möchte alle doppelten Wörter entfernen also beispielsweise Hallo usw.

mein Ansatz sah in etwa so aus:
b=""
for Zeile in zeilen:
aktwort=""
for Zeichen in Zeile:
if zeichen==" "' or zeichen=="\n":
if zeichen not in b:
b+=zeichen

Natürlich funktioniert das nicht, weil ich Probleme habe, ein Wort zu betrachten.
Für eine Idee wäre ich wirklich dankbar, mich lässt das nicht los :-(

Danke :)
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst die resultierenden Worte schon in eine Datenstruktur schreiben. Also so lange Zeichen aufsammeln bis du an ein Trennzeichen kommst, und das was du bis dahin aufgesammelt hast, musst du dann in eine Liste schreiben, und den Puffer zum aufsammeln wieder leeren.
Melthe
User
Beiträge: 9
Registriert: Dienstag 8. Januar 2019, 17:33

Hey danke @_deets_ für deine schnelle Antwort. Ja so weit war ich gedanklich auch schon, nur habe ich schon so vieles ausprobiert und weiß nicht wie ich es umsetzen soll..Kannst du mir vielleicht auf die Sprünge helfen?Danke :) LG M
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Mir ist noch nicht ganz klar, was denn das Ergebnis sein soll.

Um ein Problem zu lösen, mußt Du es erst in Teilprobleme teilen, die dann einfacher zu lösen sind.
Hier würde ich sagen, erster Schritt wäre, alle Wörter zu sammeln und zu zählen, zweiter Schritt, die gefundenen Wörter aus der Zeilen-Liste entfernen.
Für beide Teilaufgaben braucht man eine Funktion, die eine Zeile in Wörter aufspaltet.
Da ist dann die Frage, was ist ein Wort?

Das "ohne eingebaute Funktionen benutzen" wird etwas schwierig. `for Zeile in zeilen:` benutzt die eingebauten Funktionen `iter` und `next`, `zeichen==" "'` benutzt die eingebaute Funktion str.__eq__, usw.
Melthe
User
Beiträge: 9
Registriert: Dienstag 8. Januar 2019, 17:33

@Sirius3 ich wollte das beispielsweise ein Array gegeben ist a=["Hallo hallo na wie gehts\n","Hey Hallo Bla Blub\n]
und daraus soll ein neues Array entstehen mit allen einzigartigen Wörtern.
b=["Hallo na wie gehts\n","Hey Bla Blub\n"]
Und das ganze ohne eingebaute Methoden wie Split oder so...
LG
Und Zusatz:
ich habe eigentlich hauptsächlich Probleme, wie man ein Wort betrachtet. Klar ich weiß, dass ein Wort zu ende ist, sobald ein Leerzeichen da steht, aber auch so umgesetzt funktioniert es nicht bei mir...:(
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Also ist Dir Groß-klein-Schreibung egal, Leerzeichen vor oder nach einem Wort scheinen auch wegzufallen. Das Beispiel enthält jetzt keine Kommas mehr, sind die jetzt ausgeschlossen, oder wie sollen die behandelt werden?

Es bleibt als erste Aufgabe, einen String in seine Wörter zu spalten. Im Wesentlichen also str.split nachzuprogrammieren. Vielleicht solltest Du Dich erstmal darauf konzentrieren.
Melthe
User
Beiträge: 9
Registriert: Dienstag 8. Januar 2019, 17:33

@Sirius3 genau, Groß und Kleinschreibung ist erstmal egal, Kommas soll es auch nicht geben.
Ganz genau, ich möchte eigentlich die Split Methode einfach Nachprogrammieren :-)

Ich komme wirklich nicht weiter, send help
LG:)
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann programmier sie nach. Du brauchst eine Ergebnis-Liste, und musst die Zeichen aufsammeln bis zum Trennzeichen, und die gesammelten als ein Wort in die Liste schreiben. Hab ich dir schon in der ersten Antwort gesagt.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Melthe: Den Test würde ich ”umdrehen”, ein Wort ist nicht zuende wenn ein Leerzeichen gefunden ist, sondern wenn das Zeichen kein Buchstabe mehr ist. Denn sonst hast Du zum Beispiel Satzzeichen an den Worten und 'Hallo,' ist ein anderes Wort als 'Hallo'. Gross-/Kleinschreibung möchtest Du vielleicht ebenfalls (nicht) berücksichtigen.

Das was Du Arrays nennst sind Listen in Python.

Die Beschreibung des Lösungswegs und wie das Ergebnis aussehen soll ist immer noch unverständlich. Du sagst es soll ein „Array entstehen mit allen einzigartigen Wörtern” – nur enthält das `b` was Du dann zeigst gar keine Wörter sondern ganze Zeilen die jeweils mehrere Wörter enthalten. Zudem enthält das Werte die überhaupt nicht in den Beispieleingabedaten enthalten sind. Und zwar komplett!

Und wo kommst Du bei `split()` nicht weiter? Was hast Du denn schon?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Melthe
User
Beiträge: 9
Registriert: Dienstag 8. Januar 2019, 17:33

@_deets_ danke nochmals aber wie ich auch bereits schon sagte, ich habe das Prinzip verstanden, ich habe es mehrmals stundenlang versucht nachzuprorammieren, es aber nicht geklappt hat.
Oder meinst du ich schreibe zum Spaß hier rein, weil es bei den ersten 10 Anläufen nicht funktioniert hat.

Aber ok danke, dachte das wäre eine Möglichkeit hier einen Codingansatz zu bekommen.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und meinst du ich schreibe zum Spass du brauchst eine Liste? Wo ist die? Wo ist der Code, in dem du die dir gebenen Hinweise versuchst umzusetzen? Was an den gegebenen Hinweisen ist keine "Idee"? Oder kann es sein, dass du keine Idee, aber Code haben willst?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ist eine Liste eigentlich erlaubt? Da müsste man dann ja `append()` aufrufen um ein gefundenes Wort anzuhängen, also eine ”eingebaute Funktion”. Oder müsste man das `split()` dann als Generatorfunktion schreiben und die Liste dann mit einer „list comprehension“ erstellen, damit man nur ”Syntax” und keine benannten ”Funktionen” verwendet? 🤔

Und so etwas wie `str.isalpha()` muss man sich am Ende wohl auch selbst implementieren. Und `str.lower()` zumindest für Buchstaben. Und auf ASCII sollte man das dann vielleicht auch einschränken, denn für den gesamten Unicode-Zeichenvorrat möchte man das eher nicht selbst programmieren.

Ich finde die Einschränkungen unter denen das umgesetzt werden soll ja ziemlich willkürlich gewählt. Man kann solche Einschränkungen eigentlich nur sinnvoll stellen/begründen wenn man die Lösung kennt, und weiss was da alles gebraucht wird. Was ist denn der Grund sich dermassen unnatürlich einzuschränken?

Zum Code: Der fängt für die `split()`-Funktion mit ``def split(line):`` an. Und am Ende muss dann ein ``return words`` ausgeführt werden. Was hast Du denn für ”dazwischen” jetzt schon gemacht?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das Trennen der Wörter könnte man so nachprogrammieren:

Code: Alles auswählen

BUCHSTABEN = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

def gib_worte(text):
    worte = []
    puffer = []
    for zeichen in text:
        if zeichen in BUCHSTABEN:
            puffer.append(zeichen)
        else:
            if len(puffer) > 0:
                # Inhalt des Puffers als neues Wort anfügen
                # (wird nicht ausgeführt, wenn Puffer leer ist,
                #  z.B. bei Leerzeichen nach einem Komma)
                worte.append(''.join(puffer))
                # Puffer leeren für das nächste Wort
                puffer = []
    if len(puffer) > 0:
        # Puffer hat noch Inhalt, wenn letztes Zeichen ein Buchstabe war
        # -> restlichen Inhalt als neues Wort anfügen
        worte.append(''.join(puffer))
    return worte

def test():
    print(gib_worte("Hallo, na du wie gehts\n"))
    print(gib_worte("Hallo na\n"))
    print(gib_worte("na wie Wochenende\n"))

if __name__ == '__main__':
    test()
Noch ein paar Anmerkungen: Anstatt der Liste mit join() ginge für einen Anfänger IMHO auch das Plus-Rechnen mit Strings. Das else-if habe ich bewusst so hingeschrieben, damit es anfängerfreundlicher ist. Eigentlich würde ich da ein elif verwenden. Anstelle des expliziten len()-Tests geht in Python auch einfach if puffer. Weiterhin ginge anstatt einer neuen Liste auch puffer.clear(), wobei ich clear() echt selten in Python-Code sehe und man halt eher zum Neuanlegen der Datenstruktur tendiert. Zudem könnte BUCHSTABEN ein Set sein, weil damit effizienter erkannt wird, ob ein Element (hier: Zeichen) enthalten ist.

Wie man sieht, muss man noch ein paar Sonderfälle beachten, wenn der Puffer nicht befüllt ist sowie wenn er nach Ende der Schleife noch Inhalt hat. Wobei der letzte Test unnötig ist, wenn der zu verarbeitende Text immer ein Newline-Zeichen am Ende hat. Es ist aber IMHO besser, hier auf der sicheren Seite zu sein als wenn sich die Anforderungen später mal ändern und man weiterhin auf die - dann fehlerhafte - Funktionalität vertraut.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn man sich auf ASCII Klein- und Grossbuchstaben beschränkt, kann man den Test auch als ``if 'a' <= zeichen <= 'z' or 'A' <= zeichen <= 'Z':`` ausdrücken.

`list.append()`, `str.join()`, und `len()` sind natürlich streng genommen eingebaute Funktionen, die ja nicht erlaubt sind. 🙂

”In echt” würde ich die Funktion wohl so schreiben:

Code: Alles auswählen

import re

get_words = re.compile('[a-zA-Z]+').findall

print(get_words('Hallo, na du wie gehts\n'))
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und hier zum Spaß mal ohne Benutzung einer Python-Schleife:

Code: Alles auswählen

from functools import partial
from itertools import dropwhile, takewhile
from string import ascii_letters

LETTERS = set(string.ascii_letters)

def skip_nonletters(iterator):
    return dropwhile(LETTERS.isdisjoint, iterator)

def next_word(iterator):
    iterator = skip_nonletters(iterator)
    letters = takewhile(LETTERS.__contains__, iterator)
    return ''.join(letters)

def get_words(text):
    get_word = partial(next_word, iter(text))
    return list(iter(get_word, ''))

def test():
    print(get_words("Hallo, na du wie gehts\n"))
    print(get_words("Hallo na\n"))
    print(get_words("na wie Wochenende\n"))

if __name__ == '__main__':
    test()
EDIT: Ich würde das in der Praxis ebenfalls mit re.findall() lösen, aber das wäre ja langweilig...
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Na wenn alle möglichen Funktionen erlaubt sind, dann würde ich das mit den ASCII-Buchstaben sein lassen und `isalpha()` auf Zeichenketten benutzen:

Code: Alles auswählen

def skip_nonletters(iterator):
    return dropwhile(lambda c: not c.isalpha(), iterator)


def next_word(iterator):
    iterator = skip_nonletters(iterator)
    letters = takewhile(lambda c: c.isalpha(), iterator)
    return ''.join(letters)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Alternative Lösung mit `itertools`:

Code: Alles auswählen

#!/usr/bin/env python3
from operator import itemgetter
from itertools import groupby


def get_words(text):
    groups = groupby(((c.isalpha(), c) for c in text), itemgetter(0))
    return [
        ''.join(map(itemgetter(1), group))
        for is_word, group in groups if is_word
    ]


def test():
    print(get_words('Hallo, na du wie gehts\n'))
    print(get_words('Hallo na\n'))
    print(get_words('na wie Wochenende\n'))


if __name__ == '__main__':
    test()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der Ansatz mit groupby() lässt sich noch etwas knackiger formulieren, wenn nur Strings erlaubt sind:

Code: Alles auswählen

from itertools import groupby

def get_words(text):
    return [''.join(letters) for is_word, letters
            in groupby(text, str.isalpha) if is_word]

def test():
    print(get_words('Hallo, na du wie gehts\n'))
    print(get_words('Hallo na\n'))
    print(get_words('na wie Wochenende\n'))


if __name__ == '__main__':
    test()
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Der reguläre Ausdruck ist übrigens trotzdem fast doppelt so schnell (Rechner ist schon etwas älter):

Code: Alles auswählen

In [3]: %paste
from itertools import groupby
import re

def get_words_groupby(text):
    return [''.join(letters) for is_word, letters
            in groupby(text, str.isalpha) if is_word]

def get_words_re(text):
    return re.findall('[a-zA-Z]+', text)

def test():
    lines = ['Hallo, na du wie gehts\n', 'Hallo na\n', 'na wie Wochenende\n']
    for line in lines:
        words = get_words_groupby(line)
        assert words == get_words_re(line)
        print(words)

if __name__ == '__main__':
    test()

## -- End pasted text --
['Hallo', 'na', 'du', 'wie', 'gehts']
['Hallo', 'na']
['na', 'wie', 'Wochenende']

In [4]: %timeit get_words_groupby('Hallo, na du wie gehts\n')
26.5 µs ± 1.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [5]: %timeit get_words_re('Hallo, na du wie gehts\n')
14 µs ± 409 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Antworten