Próbuję pogrupować ciągi binarne określonych liczb na podstawie liczby 1 w ciągu.
To nie działa:
s = "0 1 3 7 8 9 11 15"
numbers = map(int, s.split())
binaries = [bin(x)[2:].rjust(4, '0') for x in numbers]
one_groups = dict.fromkeys(range(5), [])
for x in binaries:
one_groups[x.count('1')] += [x]
Oczekiwany słownik one_groups
musi być
{0: ['0000'],
1: ['0001', '1000'],
2: ['0011', '1001'],
3: ['0111', '1011'],
4: ['1111']}
Ale rozumiem
{0: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
1: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
2: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
3: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
4: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111']}
Jak dotąd jedyne, co zadziałało, to jeśli użyję one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
zamiastone_groups[x.count('1')] += [x]
Ale dlaczego tak jest? Jeśli dobrze pamiętam, czy nie dict[key]
powinno zwracać wartości tego słownika, podobnie jak dict.get(key)
działa? Widziałem ten wątek Dlaczego dict.get (klucz) zamiast dict [klucz]? ale nie odpowiedziałem na moje pytanie w tym konkretnym przypadku, ponieważ wiem na pewno, że program nie jest przeznaczony do uzyskaniaKeyError
Próbowałem też, one_groups[x.count('1')].append(x)
ale to też nie działa.
python
dictionary
SpectraXCD
źródło
źródło
get
zwraca,None
jeśli klucz nie istnieje lub podana jest wartość domyślna, a operator indeksu[]
zgłasza błąd, jeśli klucz nie istnieje.bin(x)[2:].rjust(4, '0')
można uprościć'{:0>4b}'.format(x)
.binaries
nie ma związku z pytaniem, więc możesz po prostu podać jego wartość.Odpowiedzi:
Problemem jest zmienność:
one_groups = dict.fromkeys(range(5), [])
- przekazuje tę samą listę jako wartość do wszystkich kluczy . Więc jeśli zmienisz jedną wartość, zmienisz je wszystkie.Jest to w zasadzie to samo, co powiedzenie:
Jeśli chcesz użyć nowej listy, musisz to zrobić w pętli - albo w
for
pętli jawnej , albo w zrozumieniu nagrania:Ta funkcja „wykona”
[]
(co jest równelist()
) dla każdego klucza, tworząc wartości z różnymi listami.Dlaczego
get
działa Ponieważ jawnie bierzesz aktualną listę, ale+
tworzy nową listę wyników. I nie ma znaczenia, czy jest toone_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
alboone_groups[x.count('1')] = one_groups[x.count('1')] + [x]
- co ważne jest to, że nie ma+
.Wiem, że wszyscy mówią, że
a+=b
jest po prostu słusznya=a+b
, ale implementacja może być inna w celu optymalizacji - w przypadku list+=
wynika tylko z.extend
tego, że wiemy, że chcemy, aby nasz wynik był w bieżącej zmiennej, więc tworzenie nowej listy byłoby marnowaniem pamięci.źródło
mylist = [[] * 5] * 5
i jakmylist = [[] for x in range(5)] * 5
to naprawiłem. Zrozumiałem, że dla szybkiego wyjaśnienia dzieje się tak ze względu na zmienne wskazujące adres pamięci tej pustej listy. Czy to oznacza również, że problem nie wystąpiłby, jeśli zamiast tego użyłem prymitywów?one_groups[x.count('1')] += [x]
ponieważ nie możesz dodać listy do typu prymitywnego. Lepszym rozwiązaniem jest użycie defaultdict.+
wywołuje__add__
i zwraca nowy obiekt, podczas gdy+=
wywołuje__iadd__
, i nie jest wymagane, aby zwrócić nowy obiektProblem polega na użyciu
one_groups = dict.fromkeys(range(5), [])
(To przekazuje tę samą listę jako wartość do wszystkich kluczy. Więc jeśli zmienisz jedną wartość, zmienisz je wszystkie)
Możesz użyć tego zamiast:
one_groups = {i:[] for i in range(5)}
(Ta funkcja „wykona” [] (co jest równe list ()) dla każdego klucza, tworząc wartości z różnymi listami.)
źródło
To jest pomoc na temat
fromkeys
metody dykta .To znaczy, że klawisze from zaakceptują wartość, a nawet jest to możliwość wywołania, najpierw ją oceni, a następnie przypisze tę wartość do wszystkich klawiszy dict.
Listy można modyfikować w Pythonie, więc przypisuje to samo puste odwołanie do listy, a jedna zmiana wpłynie na wszystkie.
Zamiast tego użyj defaultdict:
Spowoduje to przyjęcie przypisań do nieistniejących kluczy, a wartości będą domyślnie puste na listach (w tym przypadku).
źródło