Perlish dictionary behavior

C

Chris

One nice thing about Perl that is helpful when tallying things up by
type is that if you increment a hash key and the key does not exist,
Perl puts a one there. So you can have code that does something like
this:

my %thingCounts;
foreach my $thing(<file>)
{
$thingCounts{$thing}++;
}

(I think the syntax is right, but with Perl I never am sure).

In Python, this would generate a KeyError. So you'd do something like

thingCounts = {}
for thing in file:
try:
thingCounts[thing] += 1
except KeyError:
thingCounts[thing] = 1

Is there any clever way to be able to just say, like in Perl,
for thing in file:
thingCounts[thing] += 1

and have it do the above? Perhaps with a custom dictionary class or
something? Just wondering what that might look like.

Just curious. Thanks.
-Chris
 
A

Alexander Schmolck

One nice thing about Perl that is helpful when tallying things up by
type is that if you increment a hash key and the key does not exist,
Perl puts a one there. So you can have code that does something like
this:

my %thingCounts;
foreach my $thing(<file>)
{
$thingCounts{$thing}++;
}

(I think the syntax is right, but with Perl I never am sure).

In Python, this would generate a KeyError. So you'd do something like

thingCounts = {}
for thing in file:
try:
thingCounts[thing] += 1
except KeyError:
thingCounts[thing] = 1

Is there any clever way to be able to just say, like in Perl,
for thing in file:
thingCounts[thing] += 1

and have it do the above? Perhaps with a custom dictionary class or
something? Just wondering what that might look like.

I think what you really want is a bag (like a set, but were an item might
occur more than once). Since python doesn't have bags as yet, you either have
simply implement your own (presumably based on sets) or alternatively,
something like this (not properly tested):

class DefaultDict(dict):
r"""Dictionary with a default value for unknown keys."""
def new(cls, default, noCopies=False):
self = cls()
self.default = default
if noCopies:
self.noCopies = True
else:
self.noCopies = False
return self
new = classmethod(new)
def __getitem__(self, key):
r"""If `self.noCopies` is `False` (default), a **copy** of
`self.default` is returned by default.
"""
if key in self: return self.get(key)
if self.noCopies: return self.setdefault(key, self.default)
else: return self.setdefault(key, copy.copy(self.default))

[In principle inheriting from dict is a bit untidy (since DefaultDict is not
strictly substitutable for dict), but since it should be both faster and
generally more convinient I guess it's OK]

'as
 
L

Larry Bates

You can do this with:

thingCounts={}
for thing in file:
thingCounts[thing]=thingCounts.get(thing, 0)+1

Larry Bates
Syscon, Inc.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top