Zadanie z matury 2018

Odpowiedz Nowy wątek
2018-12-09 15:38
0

Znajdź słowo, w którym występuje największa liczba różnych liter. Wypisz to słowo i liczbę
występujących w nim różnych liter. Jeśli słów o największej liczbie różnych liter jest więcej
niż jedno, wypisz pierwsze z nich pojawiające się w pliku z danymi.
Zrobilem takie cos i nie wiem co dalej:


slowo=open("sygnaly.txt")
slownik={}
for znak in slowo:
    slownik[znak]=0
print(len(slownik))

Pozostało 580 znaków

2018-12-09 15:49
0
  1. W pliku są SŁOWA ODDZIELONE ZNAKIEM NOWEJ LINII, a nie jedno słowo :) (tu coś będzie o tym, jak to rozdzielić https://www.pythonforbeginners.com/dictionary/python-split)
  2. Potrzebujesz fora w forze.
    for slowo in slowa:
        znaki_w_slowie = Set()
        for znak in list(slowo):
            znaki_w_slowie.add(znak)

    Set zawiera tylko unikalne elementy, więc liczba unikalnych liter w słowie jest równa len(znaki_w_slowie)
    Jeszcze kilka poprawek i gotowe :)

EDIT
W zasadzie to można tworzyć Set z list, więc równie dobrze można zrobić znaki_w_slowie = Set(list(slowo)) i drugi for nie jest potrzebny.

edytowany 2x, ostatnio: kamillapinski, 2018-12-09 15:52
@kamillapinski: sam str wystarczy, nie trzeba z niego robić listy, bo str też jest iterowalne :) więc set(slowo) będzie szybsze w tym wypadku - grski 2018-12-09 16:21

Pozostało 580 znaków

2018-12-09 15:54
0

czyli do mojego kodu mam dopisać twój czy cały mój mam usunąć ?

Pozostało 580 znaków

2018-12-09 16:13
0
result = {'word': '', 'unique_chars': 0}
with open('xd') as f:
    for line in f:
        word = line.strip().lower()
        unique_chars = len(set(word))
        if result['unique_chars'] < unique_chars: result = {'word': word, 'unique_chars': unique_chars}
print(f"{result['word']} {result['unique_chars']}")

Tłumaczenie tego co robimy:

  1. otwieramy plik f jako context - tak by nie musieć ręcznie robić .close()
  2. jako f otworzony nam został dany plik, oraz przekształcony w iterabla, po którym możemy iterować - iterowanie po nim spowoduje wczytywanie linijka po linijce - to robimy za pomocą pętli for
  3. jako word zapisujemy sobie daną linię (bo jedno słowo jest na linijkę) i usuwamy z niego białe znaki, znaki końca linii itd. metodą strip()
  4. potem tworzymy zmienną unique_chars, która będzie równa długości seta z danego słowa, set() to nic innego jak zbiór unikalnych elemntów z danego iterabla, a stringi w pythonie są iterowalne, więc nie musimy castować na listę czy coś innego
  5. jeśli długość obecnego słowa - unique_chars jest większa od długości zapisanej w rezultacie, to wtedy uaktualniamy rezultat. Dzięki temu, że mamy tu < a nie <= to rezultat zostanie pierwszym jesli póxniej napotkamy inne słowa z taką samą liczbą znaków.
    6, wyprintowujemy wynik

Można całość jeszcze skrócić jeśli nie dbmay o czytelność a tylko o LOC:

result = {'word': '', 'unique_chars': 0}
with open('xd') as f:
    for line in f:
           if  result['unique_chars'] < len(set(line.strip().lower())): result = {'word': line.strip().lower(), 'unique_chars': len(set(line.strip()))}

Edit - nie wiem, czy A i a są tutaj traktowane jako różne litery, ale jeśli tak, to trzeba wyrzucić .lower()

edytowany 3x, ostatnio: grski, 2018-12-09 16:18

Pozostało 580 znaków

2018-12-09 19:37
2

A dla leniwych (jak akurat lubią tracić mało czasu w trakcie matury), oto szybkie rozwiązanie:

with open("sygnaly.txt") as f:
    lines = f.read().splitlines()
    m = max(lines, key=lambda s: len(set(s)))
    print(m, len(set(m)))

Edit: wersja używająca mniej dodatkowej pamięci:

with open("sygnaly.txt") as f:
    m = max(f, key=lambda s: len(set(s)))
    print(m, len(set(m)))
edytowany 5x, ostatnio: enedil, 2018-12-09 21:11
Pokaż pozostałe 2 komentarze
@enedil zgadza się jest liniowe jeśli chodzi o pamięć/czas wykonania, ale w praktyce ładujesz całość pliku do pamięci, przy większym pliku nie jest to zbyt dobre rozwiązanie a no i tego read().splitlines() można by chyba zastąpić readlines() - grski 2018-12-09 20:42
@grski: istotnie, z taką zmianą, pamięć będzie maksymalnie liniowa względem najdłuższego słowa. - enedil 2018-12-09 20:50
@enedil nope, .readlines() też ci załaduje do pamięci plik cały :) to jest po prostu krótsza forma zapisu: read().splitlines() jak checsz mieć lazy generator to zamiast f.readlines() wystarczy po prostu... max(f, ...) :) - grski 2018-12-09 21:01
swoją drogą to używanie readlines() jest raczej odradzane https://stupidpythonideas.blo[...]adlines-considered-silly.html - grski 2018-12-09 21:02
Masz rację. Ja natomiast użyłem tej pierwszej metody, gdyż od czasu do czasu przeszkadzał mi pusty element na końcu listy (bo w końcu pliki zwykły kończyć się znakiem końca linii). - enedil 2018-12-09 21:11

Pozostało 580 znaków

2018-12-09 21:08
0

Zaproponuje swoje rozwiązanie jakby ktoś dociekliwy robił test szybkości z jakimś dużym słownikiem :).

best = ("",0)
with open("sygnaly.txt") as f:
    for line in f:
        tmp_len = len(set(line))
        if tmp_len > best[1]:
            best = (line, tmp_len)
print(*best)

Linux Mint
Arduino / Python 3.5.2
edytowany 1x, ostatnio: Guaz, 2018-12-09 21:11
Kontynuując ciekawostkę. W przypadku dłuższych słowników możemy dokonać dalszej optymalizacji np. dodając linijkę if best[1]>=len(line): continue . Jeżeli nasze słowo nie jest dłuższe od naszego obecnego best to na pewno nie będzie miało więcej unikalnych znaków. Unikamy wywoływania set() dla każdego słowa - dla słownika 3000 angielskich losowych słow zwiększa to wydajność 2x. Albo posortować słowa od największych i przerwać pętlę w momencie kiedy len(line)<=best[1]. Również 2x szybciej. Ale takie ulepszenia to już sztuka dla sztuki w tym momencie :) - AsterFV 2018-12-11 14:59
Fakt, w sumie na to nie wpadłem, a z ciekawości sprawdzałeś może jak wypadają rozwiązania innych? - Guaz 2018-12-11 19:10
W sumie to nie ale napisałrem na szybko benchmark, najpierw plik z 100k słowami potem z 10 milionami. Dla mniejszych słowników czasy są identycznie niskie 100K: Grski 93.782 ms Enedil 93.749 ms Guaz 93.752 ms Guaz_skipShorter 46.84 ms SortAndBreakOnShorter 62.163 ms mapToSetAndMax 78.119 ms -> po prostu max(map(set, f), len=key) 10M: Grski 984 ms Enedil 928 ms Guaz 875 ms Guaz_skipShorter 437 ms SortAndBreakOnShorter 593 ms mapToSetAndMax 806 ms Więc wszystkie rozwiązania maja bardzo dobre czasy. - AsterFV 2018-12-12 10:09
Faktycznie, różnica niewielka, myślałem że będą większe różnice ^^. Dzięki za zaspokojenie ciekawości :) - Guaz 2018-12-12 18:27

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0