2016-02-25 13 views
9

Mam ciąg znaków ze słowami oddzielonymi spacjami. Odwracam ten ciąg do listy:Jak przekształcić ciąg znaków w dyktę

out = str.split() 

i policzyć ile wartości tworzone są:

print len(out) # Says 192 

Wtedy staram się usunąć wszystko z listy:

for x in out: 
    out.remove(x) 

I wtedy liczyć ponownie :

print len(out) # Says 96 

C ktoś wyjaśnić proszę, dlaczego mówi 96 zamiast 0 ???

WIĘCEJ INFO

mój ciąg wygląda następująco: #one kota #two psy #three ptaki Nie ma duplikatów w ciągu, wszystkie słowa są unikatowe.

Więc, co robię jest:

for x in out: 
    if '#' in x: 
      ind = out.index(x) # Get current index 
      nextValue = out[ind+1] # Get next value 
      myDictionary[x] = nextValue 
      out.remove(nextValue) 
      out.remove(x) 

Problemem jest to, że nie można przenieść wszystkie Wartość par w słowniku odkąd iteracyjne tylko przez 96 przedmiotów.

Dziękuję wszystkim!

+1

"Wtedy próbuję usunąć wszystko z listy" - zagłębimy się tutaj głębiej. Dlaczego chcesz to zrobić? –

+0

Ponieważ przenoszę wartości z listy do słownika w parach, tak jak pierwsza wartość w parze to klucz, a druga jako wartość. Chodzi o to, że mój słownik jest niekompletny, ponieważ nie mogę go w pełni przejrzeć - mówi, że istnieje tylko 96 indeksów. – user4447655

+0

Jeśli możesz opublikować kod za pomocą napisu i dyktatu, którego używasz, łatwiej nam będzie zaproponować rozwiązanie. Problem może być inny niż to, co nam dałeś do tej pory. – MKreegs

Odpowiedz

9

Chyba rzeczywiście chcesz coś takiego:

s = '#one cat #two dogs #three birds' 
out = s.split() 
entries = dict([(x, y) for x, y in zip(out[::2], out[1::2])]) 

Co to jest kod robi? Złam to. Najpierw podzieliliśmy s przez białą spację na out, tak jak Ty.

Następnie wykonujemy iterację parami w out, nazywając je "x, y". Te pary stają się list krotek/par. dict() akceptuje listę rozmiarów dwóch krotek i traktuje je jako key, val.

Oto co otrzymuję, gdy próbowałem go:

$ cat tryme.py 

s = '#one cat #two dogs #three birds' 
out = s.split() 
entries = dict([(x, y) for x, y in zip(out[::2], out[1::2])]) 

from pprint import pprint 
pprint(entries) 

$ python tryme.py 
{'#one': 'cat', '#three': 'birds', '#two': 'dogs'} 
+0

Tak, to działa! Dziękuję bardzo. Czy istnieje sposób, w jaki mógłbym włączyć warunek do tego procesu? Ponieważ muszę zmodyfikować niektóre wartości przed przekazaniem ich do słownika. Muszę pozbyć się znaku hash, czy to przez wpisy = dict ([(x [1:], y) dla x, y w zip (out [:: 2], out [1 :: 2])]), ale w niektórych przypadkach musiałbym zmodyfikować pewne znaki, na przykład, jeśli słowo zawiera "słowo kluczowe", muszę je zastąpić innym słowem. – user4447655

+0

Przepisz "spisanie ze zrozumieniem" jako tradycyjną pętlę 'for'. Pierwszy wiersz jest jak "' dla klucza, val w zip (out [:: 2], out [1 :: 2]): ', a następnie możesz zrobić cokolwiek chcesz' key' lub 'val' .Dodaj je do twojego dykta w ten sposób: 'entries [key] = val' .Nie zapomnij stworzyć dyktatora na początku,' entries = {} ', np. –

+0

Dziękujemy! Doceniam twoją pomoc! – user4447655

3

Chyba nie jest specyficzny. Dlaczego próbujesz usunąć wszystko z listy? Jeśli wszystko, co musisz zrobić, to wyczyścić listę, dlaczego nie po prostu to zrobić:

out = [] 
0

Problem polega na tym, że używasz remove (x) podczas iteracji. Zmienna "out" odnosi się zarówno do funkcji usuwania, jak i do pętli for.

Wystarczy użyć

for i in range(len(out)): 
    out.remove(out[i]); 
1

Jeśli wystarczy wyczyścić listę,

użytkowania out = [] lub out.clear()

każdym razie, że wspomniany dlatego remove funkcją listy wpływa listy .

out = ['a', 'b', 'c', 'd', 'e', 'f'] 
for x in out: 
    out.remove(x) 
    print(x) 

wtedy wynik jest poniżej:

c e

To dokładnie połowa pełnej listy. Tak więc, w przypadku, masz 96 (połowa 192) z 192.

12

chodzi o to, co rzeczywiście wydarzyło się w dla pętli:

ZPython for statement documentation:

The lista wyrażeń jest oceniana raz; powinien dać obiekt iterowalny . Iterator jest tworzony dla wyniku expression_list. Pakiet jest następnie wykonywany po dla każdej pozycji dostarczonej przez iterator , w porządku rosnących indeksów. Każdy element z kolei jest przypisany do listy docelowej z listą przy użyciu standardowych reguł dla przydziałów, , a następnie pakiet jest wykonywany. Gdy elementy są wyczerpane (co jest natychmiast, gdy sekwencja jest pusty), apartament w klauzuli else, jeżeli występuje, jest wykonywane, a loopkończy.

Myślę, że najlepiej pokazać za pomocą ilustracji .

Teraz załóżmy, że masz iterable object (takich jak list) tak:

out = [a, b, c, d, e, f] 

Co się stanie, gdy robisz for x in out jest to, że tworzy wewnętrzną podziałowe który wygląda tak (ja zilustrować go z symbol ^):

[a, b, c, d, e, f] 
^ <-- here is the indexer 

Co zwykle się zdarzyć, że: jak zakończyć jeden cykl swojej pętli, przesuwa Indexer przekazania takiego:

[a, b, c, d, e, f] #cycle 1 
^ <-- here is the indexer 

[a, b, c, d, e, f] #cycle 2 
    ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 3 
    ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 4 
     ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 5 
      ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 6 
       ^<-- here is the indexer 

#finish, no element is found anymore! 

Jak widać, urządzenie podziałowe utrzymuje naprzód do końca listy , niezależnie od tego, co się stało z listy!

Zatem kiedy robisz remove, to co się wewnętrznie:

[a, b, c, d, e, f] #cycle 1 
^ <-- here is the indexer 

[b, c, d, e, f] #cycle 1 - a is removed! 
^ <-- here is the indexer 

[b, c, d, e, f] #cycle 2 
    ^<-- here is the indexer 

[c, d, e, f] #cycle 2 - c is removed 
    ^<-- here is the indexer 

[c, d, e, f] #cycle 3 
    ^<-- here is the indexer 

[c, d, f] #cycle 3 - e is removed 
    ^<-- here is the indexer 

#the for loop ends 

Zauważ, że istnieją tylko 3 cykle tam zamiast 6 cykli (!!) (która jest liczbą elementów z pierwotnej listy). Dlatego właśnie pozostawiłeś półlen z oryginalnego len, ponieważ jest to liczba cykli wymaganych do ukończenia pętli po usunięciu z niej jednego elementu dla każdego cyklu.


Jeśli chcesz wyczyścić listę, po prostu zrobić:

if (out != []): 
    out.clear() 

albo, alternatywnie, aby usunąć element, jeden po drugim, trzeba to zrobić na odwrót - od koniec do początku. Użyj reversed:

for x in reversed(out): 
    out.remove(x) 

Teraz, to dlaczego praca reversed? Jeśli indeksator będzie posuwał się naprzód, czy nie powinien również działać reversed, ponieważ numer elementu jest w każdym razie zmniejszony o jeden na cykl?

Nie, to nie jest tak,

Ponieważ reversed metoda zmienia drogę do wewnętrznego indekser dzieła! To, co się stało podczas używania metody reversed, to: , aby wewnętrzny indeksator przesuwał się w tył (od końca) zamiast naprzód.

Aby zilustrować, to jest to, co zwykle się dzieje:

[a, b, c, d, e, f] #cycle 1 
       ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 2 
      ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 3 
     ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 4 
    ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 5 
    ^<-- here is the indexer 

[a, b, c, d, e, f] #cycle 6 
^ <-- here is the indexer 

#finish, no element is found anymore! 

I tak, kiedy wykonujesz jedno usunięcie w cyklu, to nie ma wpływu na sposób indeksowania działa:

[a, b, c, d, e, f] #cycle 1 
       ^<-- here is the indexer 

[a, b, c, d, e] #cycle 1 - f is removed 
       ^<-- here is the indexer 

[a, b, c, d, e] #cycle 2 
      ^<-- here is the indexer 

[a, b, c, d] #cycle 2 - e is removed 
      ^<-- here is the indexer 

[a, b, c, d] #cycle 3 
     ^<-- here is the indexer 

[a, b, c] #cycle 3 - d is removed 
     ^<-- here is the indexer 

[a, b, c] #cycle 4 
    ^<-- here is the indexer 

[a, b] #cycle 4 - c is removed 
    ^<-- here is the indexer 

[a, b] #cycle 5 
    ^<-- here is the indexer 

[a] #cycle 5 - b is removed 
    ^<-- here is the indexer 

[a] #cycle 6 
^ <-- here is the indexer 

[] #cycle 6 - a is removed 
^ <-- here is the indexer 

Nadzieja ilustracja pomaga zrozumieć, co się dzieje wewnętrznie ...

+1

Jest to jedno z najlepszych wyjaśnień dotyczących modyfikowania podczas iteracji, jakie kiedykolwiek widziałem. Chciałbym móc to powtórzyć więcej niż raz! –

+1

Dałeś jednoznaczne wyjaśnienie mojej odpowiedzi! Dziękuję bardzo! – user4447655

+1

Właśnie napisałem mały przykład, dziękuję za odpowiedź na faktyczne pytanie! – pyInTheSky

2

Problem, który napotykasz, jest wynikiem modyfikacji li st podczas iteracji nad nim. Kiedy element zostanie usunięty, wszystko po nim zostanie przesunięte do przodu o jeden indeks, ale iterator nie uwzględnia zmiany i kontynuuje zwiększając indeks, do którego ostatnio był dostęp. Iterator pomija więc co drugi element na liście, dlatego pozostaje ci połowa liczby elementów.

Najprostszym bezpośrednie rozwiązanie problemu jest iteracyjne nad kopii z out, używając notacji plasterka:

for x in out[:]: 
    # ... 
    out.remove(x) 

Istnieje jednak głębszy tu pytanie: dlaczego trzeba usunąć elementy z lista w ogóle? Z twoim algorytmem masz gwarancję, że skończysz z pustą listą, która jest dla ciebie bezużyteczna. Byłoby prostsze i bardziej wydajne, aby po prostu powtórzyć listę bez usuwania elementów.

Gdy skończysz z listą (po bloku for-loop), możesz ją jawnie usunąć (używając słowa kluczowego del) lub po prostu pozostawić ją dla systemu do czyszczenia pamięci Pythona.

Pozostaje jeszcze jeden problem: łączymy bezpośrednią iterację na liście z referencjami opartymi na indeksie. Używanie for x in out powinno być zwykle ograniczone do sytuacji, w których chcesz uzyskać dostęp do każdego elementu niezależnie od innych. Jeśli chcesz pracować z indeksami, użyj for i in range(len(out)) i uzyskaj dostęp do elementów za pomocą out[i].

Ponadto, można użyć zrozumieniem słownika zrealizować całe swoje zadania w jednej linii pythonic wypowiedzi:

my_dictionary = {out[i]: out[i + 1] for i in range(len(out)) if "#" in out[i]} 

Innym pythonic alternatywą byłoby skorzystać z faktu, że każdy parzystych element jest kluczem, a każdy nieparzysty element jest wartością (musisz przyjąć, że wynik listy str.split() konsekwentnie podąża za tym wzorcem) i użyć zip na podstronach parzystych i nieparzystych.

my_dictionary = dict(zip(out[::2], out[1::2])) 
2

Uważam, że chcesz śledzić.

>>> a = '#one cat #two dogs #three birds' 
>>> b = { x.strip().split(' ')[0] : x.strip().split(' ')[-1] for x in a.strip().split('#') if len(x) > 0 } 
>>> b 
{'three': 'birds', 'two': 'dogs', 'one': 'cat'} 

Albo jeszcze lepiej

>>> b = [ y for x in a.strip().split('#') for y in x.strip().split(' ') if len(x) > 0 ] 
>>> c = { x: y for x,y in zip(b[0::2],b[1::2]) } 
>>> c 
{'three': 'birds', 'two': 'dogs', 'one': 'cat'} 
>>> 
1

Problem jest, gdy wartość z listy usunąć, zwłaszcza że lista przywraca jej wartości dynamicznie. Oznacza to, że podczas wykonywania out.remove(ind) i out.remove(ind+1) wartości w tych indeksach są usuwane, , ale są zastępowane nowymi wartościami, które są poprzednikami poprzedniej wartości.

Dlatego, aby tego uniknąć trzeba zaimplementować kod w następujący sposób:

out = [] 
out = '#one cat #two dogs #three birds'.split() 

print "The list is : {0} \n".format(out) 
myDictionary = dict() 

for x in out: 

    if '#' in x: 
     ind = out.index(x) # Get current index 
     nextValue = out[ind+1] # Get next value 
     myDictionary[x] = nextValue 

out = [] # #emptying the list 
print("The dictionary is : {0} \n".format(myDictionary)) 

Tak, po zakończeniu przenoszenia wartości z listy do słownika, możemy bezpiecznie opróżnić out przez użyciu out = []

Powiązane problemy