Hoe werkt collections.defaultdict?

Ik heb de voorbeelden in python-documenten gelezen, maar kan er nog steeds niet achter komen wat deze methode betekent. Kan iemand helpen? Hier zijn twee voorbeelden uit de python-documenten

>>> from collections import defaultdict
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

en

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

de parameters inten listzijn waarvoor?


Antwoord 1, autoriteit 100%

Normaal gesproken geeft een Python-woordenboek een KeyErrorals je een item probeert te krijgen met een sleutel die momenteel niet in het woordenboek staat. Het defaultdictdaarentegen zal gewoon alle items creëren die je probeert te openen (mits ze natuurlijk nog niet bestaan). Om zo’n “standaard” item te maken, roept het het functie-object aan dat u doorgeeft aan de constructor (meer precies, het is een willekeurig “oproepbaar” object, dat functie- en type-objecten omvat). Voor het eerste voorbeeld worden standaarditems gemaakt met int(), wat het gehele object 0als resultaat geeft. Voor het tweede voorbeeld worden standaarditems gemaakt met list(), wat een nieuw leeg lijstobject retourneert.


Antwoord 2, autoriteit 37%

defaultdictbetekent dat als een sleutel niet in het woordenboek wordt gevonden, er een nieuwe invoer wordt gemaakt in plaats van dat er een KeyErrorwordt gegenereerd. Het type van dit nieuwe item wordt gegeven door het argument van defaultdict.

Bijvoorbeeld:

somedict = {}
print(somedict[3]) # KeyError
someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0

Antwoord 3, autoriteit 16%

standaard

“Het standaardwoordenboek bevat de methode setdefault() voor het ophalen van een waarde en het instellen van een standaardwaarde als de waarde niet bestaat. Daarentegen laat defaultdictde aanroeper de standaard(waarde die moet worden geretourneerd) specificeren ) vooraan wanneer de container wordt geïnitialiseerd.”

zoals gedefinieerd door Doug Hellmannin The Python Standard Library by example

Hoe gebruik je standaarddict

Standaarddictaat importeren

>>> from collections import defaultdict

Initialiseer standaarddict

Initialiseer het door

. door te geven

callableals eerste argument (verplicht)

>>> d_int = defaultdict(int)
>>> d_list = defaultdict(list)
>>> def foo():
...     return 'default value'
... 
>>> d_foo = defaultdict(foo)
>>> d_int
defaultdict(<type 'int'>, {})
>>> d_list
defaultdict(<type 'list'>, {})
>>> d_foo
defaultdict(<function foo at 0x7f34a0a69578>, {})

**kwargsals tweede argument (optioneel)

>>> d_int = defaultdict(int, a=10, b=12, c=13)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})

of

>>> kwargs = {'a':10,'b':12,'c':13}
>>> d_int = defaultdict(int, **kwargs)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})

Hoe werkt het

Net als een onderliggende klasse van een standaardwoordenboek, kan het dezelfde functies uitvoeren.

Maar in het geval dat een onbekende sleutel wordt doorgegeven, wordt de standaardwaarde geretourneerd in plaats van een fout. Bijvoorbeeld:

>>> d_int['a']
10
>>> d_int['d']
0
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12, 'd': 0})

Als u de standaardwaarde wilt wijzigen, overschrijft u default_factory:

>>> d_int.default_factory = lambda: 1
>>> d_int['e']
1
>>> d_int
defaultdict(<function <lambda> at 0x7f34a0a91578>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0})

of

>>> def foo():
...     return 2
>>> d_int.default_factory = foo
>>> d_int['f']
2
>>> d_int
defaultdict(<function foo at 0x7f34a0a0a140>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0, 'f': 2})

Voorbeelden in de vraag

Voorbeeld 1

Aangezien int is doorgegeven als default_factory, retourneert elke onbekende sleutel standaard 0.

Als de tekenreeks nu in de lus wordt doorgegeven, wordt het aantal van die alfabetten in d verhoogd.

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> d.default_factory
<type 'int'>
>>> for k in s:
...     d[k] += 1
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
>>> d
defaultdict(<type 'int'>, {'i': 4, 'p': 2, 's': 4, 'm': 1})

Voorbeeld 2

Omdat een lijst is doorgegeven als default_factory, zal elke onbekende (niet-bestaande) sleutel standaard [ ](dwz lijst) retourneren.

Als de lijst met tuples nu in de lus wordt doorgegeven, wordt de waarde toegevoegd in de d[kleur]

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> d.default_factory
<type 'list'>
>>> for k, v in s:
...     d[k].append(v)
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
>>> d
defaultdict(<type 'list'>, {'blue': [2, 4], 'red': [1], 'yellow': [1, 3]})

Antwoord 4, autoriteit 4%

Woordenboeken zijn een handige manier om gegevens op te slaan om ze later op naam (sleutel) te kunnen terugvinden. Sleutels moeten unieke, onveranderlijke objecten zijn en zijn doorgaans tekenreeksen. De waarden in een woordenboek kunnen van alles zijn. Voor veel toepassingen zijn de waarden eenvoudige typen, zoals gehele getallen en tekenreeksen.

Het wordt interessanter wanneer de waarden in een woordenboek collecties zijn (lijsten, dictten, enz.) In dit geval moet de waarde (een lege lijst of dict) de eerste keer dat een bepaalde sleutel wordt gebruikt. Hoewel dit relatief eenvoudig is om handmatig te doen, automatiseert en vereenvoudigt het standaarddict-type dit soort operaties.
Een standaarddict werkt precies zoals een normale dict, maar het wordt geïnitialiseerd met een functie (“standaard fabriek”) die geen argumenten aanneemt en de standaardwaarde biedt voor een niet-functionele toets.

Een standaardictiver zal nooit een KeyError verhogen. Elke sleutel die niet bestaat, krijgt de waarde die wordt geretourneerd door de standaardfabriek.

from collections import defaultdict
ice_cream = defaultdict(lambda: 'Vanilla')
ice_cream['Sarah'] = 'Chunky Monkey'
ice_cream['Abdul'] = 'Butter Pecan'
print(ice_cream['Sarah'])
>>>Chunky Monkey
print(ice_cream['Joe'])
>>>Vanilla

Hier is een ander voorbeeld van het gebruik van defaidendeict, we kunnen complexiteit

verminderen

from collections import defaultdict
# Time complexity O(n^2)
def delete_nth_naive(array, n):
    ans = []
    for num in array:
        if ans.count(num) < n:
            ans.append(num)
    return ans
# Time Complexity O(n), using hash tables.
def delete_nth(array,n):
    result = []
    counts = defaultdict(int)
    for i in array:
        if counts[i] < n:
            result.append(i)
            counts[i] += 1
    return result
x = [1,2,3,1,2,1,2,3]
print(delete_nth(x, n=2))
print(delete_nth_naive(x, n=2))

Concluderend, wanneer u een woordenboek nodig heeft, en de waarde van elk element moet beginnen met een standaardwaarde, gebruik een standaardictiver.


Antwoord 5, Autoriteit 3%

Er is hier een goede uitleg van defaultdicts: http://ludovf.net/blog/python-collections-defaultdict /

Kortom, de parameters inten listzijn functies die u doorgeeft. Onthoud dat Python functienamen als argumenten accepteert. intretourneert standaard 0 en listretourneert een lege lijst wanneer aangeroepen tussen haakjes.

In normale woordenboeken, als ik in uw voorbeeld d[a]probeer aan te roepen, krijg ik een foutmelding (KeyError), aangezien alleen de toetsen m, s, i en p bestaan en de toets a heeft niet geïnitialiseerd. Maar in een standaarddictaat neemt het een functienaam als argument, wanneer je een sleutel probeert te gebruiken die niet is geïnitialiseerd, roept het gewoon de functie aan die je hebt doorgegeven en wijst de geretourneerde waarde toe als de waarde van de nieuwe sleutel.


Antwoord 6, autoriteit 2%

Het gedrag van defaultdictkan gemakkelijk worden nagebootst met dict.setdefaultin plaats van d[key]in elk gesprek.

Met andere woorden, de code:

from collections import defaultdict
d = defaultdict(list)
print(d['key'])                        # empty list []
d['key'].append(1)                     # adding constant 1 to the list
print(d['key'])                        # list containing the constant [1]

is gelijk aan:

d = dict()
print(d.setdefault('key', list()))     # empty list []
d.setdefault('key', list()).append(1)  # adding constant 1 to the list
print(d.setdefault('key', list()))     # list containing the constant [1]

Het enige verschil is dat bij gebruik van defaultdictde lijstconstructor slechts één keer wordt aangeroepen en bij gebruik van dict.setdefaultde lijstconstructor vaker wordt aangeroepen (maar de code kan worden herschreven om dit te voorkomen, indien echt nodig).

Sommigen zullen misschien beweren dat er prestatieoverwegingen zijn, maar dit onderwerp is een mijnenveld. Dit bericht laat zien dat er geen grote prestatiewinst is bij het gebruik van defaultdict , bijvoorbeeld.

IMO, defaultdict is een verzameling die meer verwarring dan voordelen aan de code toevoegt. Nutteloos voor mij, maar anderen kunnen er anders over denken.


Antwoord 7

Omdat de vraag gaat over “hoe het werkt”, willen sommige lezers misschien meer moeren en bouten zien. De methode in kwestie is in het bijzonder de methode __missing__(key). Zie: https://docs.python.org/2/library/collections .html#defaultdict-objects.

Concreet laat dit antwoord zien hoe je __missing__(key)op een praktische manier kunt gebruiken:
https://stackoverflow.com/a/17956989/1593924

Om te verduidelijken wat ‘callable’ betekent, is hier een interactieve sessie (vanaf 2.7.6 maar zou ook in v3 moeten werken):

>>> x = int
>>> x
<type 'int'>
>>> y = int(5)
>>> y
5
>>> z = x(5)
>>> z
5
>>> from collections import defaultdict
>>> dd = defaultdict(int)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd = defaultdict(x)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd['a']
0
>>> dd
defaultdict(<type 'int'>, {'a': 0})

Dat was het meest typische gebruik van defaultdict (behalve het zinloze gebruik van de x-variabele). U kunt hetzelfde doen met 0 als de expliciete standaardwaarde, maar niet met een eenvoudige waarde:

>>> dd2 = defaultdict(0)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    dd2 = defaultdict(0)
TypeError: first argument must be callable

In plaats daarvan werkt het volgende omdat het een eenvoudige functie doorgeeft (het creëert on-the-fly een naamloze functie die geen argumenten nodig heeft en altijd 0 retourneert):

>>> dd2 = defaultdict(lambda: 0)
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {})
>>> dd2['a']
0
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {'a': 0})
>>> 

En met een andere standaardwaarde:

>>> dd3 = defaultdict(lambda: 1)
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {})
>>> dd3['a']
1
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {'a': 1})
>>> 

Antwoord 8

Mijn eigen 2¢: u kunt defaultdict ook subclasseren:

class MyDict(defaultdict):
    def __missing__(self, key):
        value = [None, None]
        self[key] = value
        return value

Dit kan van pas komen in zeer complexe gevallen.


Antwoord 9

De defaultdict-tool is een container in de collections-klasse van Python. Het is vergelijkbaar met de gebruikelijke woordenboekcontainer (dictaat), maar heeft één verschil: het gegevenstype van de waardevelden wordt gespecificeerd bij de initialisatie.

Bijvoorbeeld:

from collections import defaultdict
d = defaultdict(list)
d['python'].append("awesome")
d['something-else'].append("not relevant")
d['python'].append("language")
for i in d.items():
    print i

Hiermee wordt afgedrukt:

('python', ['awesome', 'language'])
('something-else', ['not relevant'])

Antwoord 10

Nou, defaultdict kan ook keyerror oproepen in het volgende geval:

   from collections import defaultdict
    d = defaultdict()
    print(d[3]) #raises keyerror

Onthoud altijd een argument aan de defaultdict te geven, zoals defaultdict(int).


Antwoord 11

Zonder defaultdictkunt u waarschijnlijk nieuwe waarden toewijzen aan onzichtbare sleutels, maar u kunt deze niet wijzigen. Bijvoorbeeld:

import collections
d = collections.defaultdict(int)
for i in range(10):
  d[i] += i
print(d)
# Output: defaultdict(<class 'int'>, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9})
import collections
d = {}
for i in range(10):
  d[i] += i
print(d)
# Output: Traceback (most recent call last): File "python", line 4, in <module> KeyError: 0

Antwoord 12

Ik denk dat het het beste kan worden gebruikt in plaats van een switch case-statement. Stel je voor dat we een switch case-statement hebben zoals hieronder:

option = 1
switch(option) {
    case 1: print '1st option'
    case 2: print '2nd option'
    case 3: print '3rd option'
    default: return 'No such option'
}

Er zijn geen switchcase-statements beschikbaar in python. We kunnen hetzelfde bereiken door defaultdictte gebruiken.

from collections import defaultdict
def default_value(): return "Default Value"
dd = defaultdict(default_value)
dd[1] = '1st option'
dd[2] = '2nd option'
dd[3] = '3rd option'
print(dd[4])    
print(dd[5])    
print(dd[3])

Het drukt af:

Default Value
Default Value
3rd option

In het bovenstaande fragment heeft ddgeen toetsen 4 of 5 en daarom drukt het een standaardwaarde af die we hebben geconfigureerd in een helperfunctie. Dit is veel leuker dan een onbewerkt woordenboek waar een KeyErrorwordt gegenereerd als de sleutel niet aanwezig is. Hieruit blijkt dat defaultdictmeer lijkt op een switch case-statement waar we ingewikkelde if-elif-elif-else-blokken kunnen vermijden.

Nog een goed voorbeeld van deze siteis:

>>> from collections import defaultdict
>>> food_list = 'spam spam spam spam spam spam eggs spam'.split()
>>> food_count = defaultdict(int) # default value of int is 0
>>> for food in food_list:
...     food_count[food] += 1 # increment element's value by 1
...
defaultdict(<type 'int'>, {'eggs': 1, 'spam': 7})
>>>

Als we proberen toegang te krijgen tot andere items dan eggsen spam, krijgen we een telling van 0.


Antwoord 13

Het standaardwoordenboek bevat de methode setdefault() voor het ophalen van een waarde en het instellen van een standaardwaarde als de waarde niet bestaat. Daarentegen laat defaultdict de beller de standaard vooraf specificeren wanneer de container wordt geïnitialiseerd.

import collections
def default_factory():
    return 'default value'
d = collections.defaultdict(default_factory, foo='bar')
print 'd:', d
print 'foo =>', d['foo']
print 'bar =>', d['bar']

Dit werkt goed zolang het gepast is dat alle sleutels dezelfde standaardwaarde hebben. Het kan met name handig zijn als de standaardwaarde een type is dat wordt gebruikt voor het aggregeren of accumuleren van waarden, zoals een lijst, set of zelfs int. De standaard bibliotheekdocumentatie bevat verschillende voorbeelden van het op deze manier gebruiken van defaultdict.

$ python collections_defaultdict.py
d: defaultdict(<function default_factory at 0x100468c80>, {'foo': 'bar'})
foo => bar
bar => default value

Antwoord 14

Kortom:

defaultdict(int)– het argument int geeft aan dat de waarden van het type int zijn.

defaultdict(list)– de lijst met argumenten geeft aan dat de waarden van het lijsttype zijn.


Antwoord 15

#dictinary and defaultdict
normaldictionary=dict()
print(type(normaldictionary))
#print(normaldictionary["keynotexisit"])
#Above normal dictionary give an error as key not present
from collections import defaultdict
defaultdict1=defaultdict()
print(type(defaultdict1))
#print(defaultdict1['keynotexisit'])
######################################
from collections import defaultdict
default2=defaultdict(int)
print(default2['keynotexist'])

https://msatutorpy.medium.com/different-between -woordenboek-en-standaardwoordenboek-cb215f682971


Antwoord 16

De documentatie en de uitleg spreken voor zich:

http://docs.python.org/library/collections.html# collections.defaultdict

De typefunctie (int/str etc.) die als argument wordt doorgegeven, wordt gebruikt om een standaardwaarde te initialiseren voor een bepaalde sleutel waar de sleutel niet in het dictaat aanwezig is.

Other episodes