473,407 Members | 2,326 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,407 software developers and data experts.

Append a new value to dict

Pat
I know it's not "fair" to compare language features, but it seems to me
(a Python newbie) that appending a new key/value to a dict in Python is
awfully cumbersome.

In Python, this is the best code I could come up with for adding a new
key, value to a dict

mytable.setdefault( k, [] ).append( v )

In Perl, the code looks like this:

$h{ $key } = $value ;

Is there a better/easier way to code this in Python than the
obtuse/arcane setdefault code?
Oct 13 '08 #1
20 3032
Pat
Pat wrote:
I know it's not "fair" to compare language features, but it seems to me
(a Python newbie) that appending a new key/value to a dict in Python is
awfully cumbersome.

In Python, this is the best code I could come up with for adding a new
key, value to a dict

mytable.setdefault( k, [] ).append( v )

In Perl, the code looks like this:

$h{ $key } = $value ;

Is there a better/easier way to code this in Python than the
obtuse/arcane setdefault code?
Naturally, right after writing my post I found that there is an easier way:

table[ k ] = v

I found that in "Python for Dummies". How apropos.
Oct 13 '08 #2
jdd
On Oct 13, 7:21*am, Pat <P...@junk.comwrote:
Is there a better/easier way to code this in Python than the
obtuse/arcane setdefault code?
foo = {'bar': 'baz'}
foo.update({'quux': 'blah'})
Oct 13 '08 #3
Pat schrieb:
I know it's not "fair" to compare language features, but it seems to me
(a Python newbie) that appending a new key/value to a dict in Python is
awfully cumbersome.

In Python, this is the best code I could come up with for adding a new
key, value to a dict

mytable.setdefault( k, [] ).append( v )

In Perl, the code looks like this:

$h{ $key } = $value ;
Whats wrong with:

mytable[key] = value

cheers
Paul

Oct 13 '08 #4
Pat wrote:
I know it's not "fair" to compare language features, but it seems to me
(a Python newbie) that appending a new key/value to a dict in Python is
awfully cumbersome.

In Python, this is the best code I could come up with for adding a new
key, value to a dict

mytable.setdefault( k, [] ).append( v )

In Perl, the code looks like this:

$h{ $key } = $value ;
There's a huge difference here:

In your Python example you're using a list. In the Perl example you're
using a scalar value.

Is there a better/easier way to code this in Python than the
obtuse/arcane setdefault code?
When just assigning a new key-value-pair there's no problem in Python.
(Just refer to the answers before.) When I switched from Perl to Python
however I commonly ran into this problem:
>>counter = {}
counter['A'] = 1
counter['A'] += 1
counter['A']
2

Ok - assigning a key-value-pair works fine. Incrementing works as well.
>>counter['B'] += 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'B'

However incrementing a non-existing key throws an exception. So you
either have to use a workaround:
>>try:
.... counter['B'] += 1
.... except KeyError:
.... counter['B'] = 1

Since this looks ugly somebody invented the setdefault method:
>>counter['B'] = counter.setdefault('B',0) + 1
And this works with lists/arrays as well. When there's no list yet
setdefault will create an empty list and append the first value.
Otherwise it will just append.

Greetings from Vienna,
mathias
Oct 13 '08 #5
>In Python, this is the best code I could come up with for
>adding a new key, value to a dict

mytable.setdefault( k, [] ).append( v )

Naturally, right after writing my post I found that there is
an easier way:

table[ k ] = v
Just to be clear...these do two VERY different things:
>>v1=42
table1={}
k='foo'
table1.setdefault(k,[]).append(v1)
table2={}
table2[k]=v1
table1, table2
({'foo': [42]}, {'foo': 42})

Note that the value in the first case is a *list* while the
value in the 2nd case, the value is a scalar. These differ in
the behavior (continuing from above):
>>v2='Second value'
table1.setdefault(k,[]).append(v2)
table2[k]=v2
table1, table2
({'foo': [42, 'Second value']}, {'foo': 'Second value'})

Note that table1 now has *two* values associated with 'foo',
while table2 only has the most recently assigned value.

Choose according to your use-case. For some of my ETL &
data-processing work, I often want the

mydict.setdefault(key, []).append(value)

version to accrue values associated with a given unique key.

-tkc


Oct 13 '08 #6
jdd:
foo = {'bar': 'baz'}
foo.update({'quux': 'blah'})
That creates a new dict, to throw it away. Don't do that. Use the
standard and more readable syntax:
foo = {...}
foo['quux'] = 'blah'
Bye,
bearophile
Oct 13 '08 #7
On Mon, 13 Oct 2008 14:10:43 +0200, Mathias Frey wrote:
However incrementing a non-existing key throws an exception. So you
either have to use a workaround:
>>try:
... counter['B'] += 1
... except KeyError:
... counter['B'] = 1

Since this looks ugly somebody invented the setdefault method:
>>counter['B'] = counter.setdefault('B',0) + 1
Nope, for this use case there is the `dict.get()` method:

counter['B'] = counter.get('B', 0) + 1

This assigns only *once* to ``counter['B']`` in every case.

`dict.setdefault()` is for situations where you really want to actually
put the initial value into the dictionary, like with the list example by
the OP.

Ciao,
Marc 'BlackJack' Rintsch
Oct 13 '08 #8
be************@lycos.com a écrit :
jdd:
>foo = {'bar': 'baz'}
foo.update({'quux': 'blah'})

That creates a new dict, to throw it away.
Just to make it clear for the easily confused ones (like me...):
bearophile is talking about the dict passed as an argument to foo.update
- not about the behaviour of dict.update itself (which of course
modifies the dict in place) !-)

Oct 13 '08 #9
At 2008-10-13T13:14:15Z, be************@lycos.com writes:
jdd:
>foo = {'bar': 'baz'}
foo.update({'quux': 'blah'})

That creates a new dict, to throw it away. Don't do that.
I use that if I'm changing many values at once, eg:

foo.update({
'quux': 'blah',
'baz' : 'bearophile',
'jdd' : 'dict',
})

instead of:

foo['quux'] = 'blah'
foo['baz'] = 'bearophile'
foo['jdd'] = 'dict'

because it seems to more clearly indicate what I'm doing, and has fewer
opportunities for types. Still, there is a performance penalty. Running
"my way" 10,000,000 times took 8.7s, and "your way" only took 4.7s. If
you're doing this in an inner loop, that may be significant. While we're on
the subject, use keyword arguments to dict like:

foo.update(dict(quux='blah', baz='bearophile', jdd='dict'))

was *much* slower, at 11.8s.
--
Kirk Strauser
The Day Companies
Oct 13 '08 #10
On Oct 13, 9:41 am, Marc 'BlackJack' Rintsch <bj_...@gmx.netwrote:
On Mon, 13 Oct 2008 14:10:43 +0200, Mathias Frey wrote:
However incrementing a non-existing key throws an exception. So you
either have to use a workaround:
>>try:
... counter['B'] += 1
... except KeyError:
... counter['B'] = 1
Since this looks ugly somebody invented the setdefault method:
>>counter['B'] = counter.setdefault('B',0) + 1

Nope, for this use case there is the `dict.get()` method:

counter['B'] = counter.get('B', 0) + 1

This assigns only *once* to ``counter['B']`` in every case.

`dict.setdefault()` is for situations where you really want to actually
put the initial value into the dictionary, like with the list example by
the OP.

Ciao,
Marc 'BlackJack' Rintsch
....and if you are using Python 2.5 or later you can use the
collections module with collections.defaultdict(list) or
collections.defaultdict(int) to do the same thing. I personally find
it easier to read.
Oct 13 '08 #11
Kirk Strauser wrote:
While we're on
the subject, use keyword arguments to dict like:

foo.update(dict(quux='blah', baz='bearophile', jdd='dict'))

was *much* slower, at 11.8s.
Presumably you would save half of that time by writing simply

foo.update(quux='blah', baz='bearophile', jdd='dict')

Cheers, BB

Oct 16 '08 #12
Pat
paul wrote:
Pat schrieb:
>I know it's not "fair" to compare language features, but it seems to
me (a Python newbie) that appending a new key/value to a dict in
Python is awfully cumbersome.

In Python, this is the best code I could come up with for adding a new
key, value to a dict

mytable.setdefault( k, [] ).append( v )

In Perl, the code looks like this:

$h{ $key } = $value ;
Whats wrong with:

mytable[key] = value

cheers
Paul
mytable[key] = value

is the code that I wound up using. It's obvious now that I know the
answer. Thank you very much to all for your help.

In a earlier question (I can't find the thread in my newsreader), I
asked about an array of dict to dict and someone supplied me with the
answer.

[state]={}
[state][city]={}
['Florida']['Tampa] = 20

It worked out perfectly and the Python code is a billion times easier to
read than the Perl version.
Of all the languages I've learned and used professionally, I'm finding
Python to be one of the best languages to learn and use.

Having Wing IDE Pro has made it a lot easier for me to learn and debug.
It does have a few bugs but they always respond by email within
several hours. Absolutely superb customer support. And no, I'm in no
way affiliated with Wingware except that I'm a satisfied customer.
Oct 16 '08 #13
However incrementing a non-existing key throws an exception.

Right. And that's exactly what I would expect, according to the
"principle of least surprise" Python tries to obey. There's simply no
way to increment a non-existent value - not without performing some
obscure implict behind-the-scenes stuff.
So you
either have to use a workaround:
>>try:
... counter['B'] += 1
... except KeyError:
... counter['B'] = 1
Or you could simply use

if counter.has_key('B'):
counter['B'] += 1
else:
counter['B'] = 1

Regards,
Frank
Oct 22 '08 #14
Frank Niemeyer:
There's simply no
way to increment a non-existent value - not without performing some
obscure implict behind-the-scenes stuff.
Like importing and using a defaultdict(int).

So you
either have to use a workaround:
*>>try:
... * counter['B'] += 1
... except KeyError:
... * counter['B'] = 1

Or you could simply use

if counter.has_key('B'):
* * counter['B'] += 1
else:
* * counter['B'] = 1
Both those are slow. Better to use:

if 'B' in counter:
counter['B'] += 1
else:
counter['B'] = 1

Or with a defaultdict:

counter = defauldict(int)
counter['B'] += 1

Bye,
bearophile
Oct 22 '08 #15
On Wed, 22 Oct 2008 10:12:56 -0700, bearophileHUGS wrote:
Frank Niemeyer:
>There's simply no
way to increment a non-existent value - not without performing some
obscure implict behind-the-scenes stuff.

Like importing and using a defaultdict(int).

So you
either have to use a workaround:
Â*>>try:
... Â* counter['B'] += 1
... except KeyError:
... Â* counter['B'] = 1

Or you could simply use

if counter.has_key('B'):
Â* Â* counter['B'] += 1
else:
Â* Â* counter['B'] = 1

Both those are slow. Better to use:

if 'B' in counter:
counter['B'] += 1
else:
counter['B'] = 1

Or with a defaultdict:

counter = defauldict(int)
counter['B'] += 1
Or:

counter['B'] = counter.get('B', 0) + 1

Ciao,
Marc 'BlackJack' Rintsch
Oct 22 '08 #16
be************@lycos.com schrieb:
Frank Niemeyer:
>There's simply no
way to increment a non-existent value - not without performing some
obscure implict behind-the-scenes stuff.

Like importing and using a defaultdict(int).
There's nothing implicit in explicitly defining some default behaviour.

Frank

Oct 23 '08 #17
Marc 'BlackJack' Rintsch:
counter['B'] = counter.get('B', 0) + 1
If you benchmark it, you will find that using the get() method it's
quite slower.

Bye,
bearophile
Oct 23 '08 #18

Frank Niemeyer wrote:
>
>However incrementing a non-existing key throws an exception.

Right. And that's exactly what I would expect, according to the
"principle of least surprise" Python tries to obey. There's simply no
way to increment a non-existent value - not without performing some
obscure implict behind-the-scenes stuff.
>So you
either have to use a workaround:
> >>try:
... counter['B'] += 1
... except KeyError:
... counter['B'] = 1

Or you could simply use

if counter.has_key('B'):
counter['B'] += 1
else:
counter['B'] = 1

Regards,
Frank
--
http://mail.python.org/mailman/listinfo/python-list

or

if 'B' in counter:
counter['B'] += 1
else:
ocunter['B'] = 1
--
View this message in context: http://www.nabble.com/Append-a-new-v...p20127415.html
Sent from the Python - python-list mailing list archive at Nabble.com.

Oct 23 '08 #19
be************@lycos.com wrote:
Marc 'BlackJack' Rintsch:
>counter['B'] = counter.get('B', 0) + 1

If you benchmark it, you will find that using the get() method it's
quite slower.
Slower than

if 'B' in counter:
counter['B'] += 1
else:
counter['B'] = 1
?

It is not slower than defaultdict which I have compared to
>counter['B'] = counter.get('B', 0) + 1
on a file with 125,000 additions default dict was significantly slower
(only ~40seconds v ~30 secs for get) and used twice the memory.

--
djc
Oct 23 '08 #20
slais-www:
Slower than
...
Okay, I seen there's a little confusion, I try to say it more clearly.
Generally this is the faster version (faster than the version with
get), especially if you use Psyco:

version 1)
if 'B' in counter:
counter['B'] += 1
else:
counter['B'] = 1

-----------------

Version using a defaultdict:
version 2)
counter['B'] += 1 #

The defaultdict case 2) is intermediate: its relative speed changes on
the basis of the frequency of already present keys. Generally the
difference between 1) and 2) isn't much, so I usually use a
defaultdict 2), that has a nicer syntax, even if it can sometimes be a
little slower than 1).

Versions with has_key or try-except or get aren't fast.

Bye,
bearophile
Oct 23 '08 #21

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: tertius | last post by:
Is there a better way to append certain chars in a string with a backslash that the example below? chr = "#$%^&_{}" # special chars to look out for str = "123 45^ & 00 0_" # string to...
6
by: M. Clift | last post by:
Hi All, I have tried to come up with a way to do this myself and all I end up with is very long code. What I have is a say item1, item4, item2, item1 etc... What I want to do is append to...
1
by: Yereth | last post by:
Hi again, still working on my xslt program and I ran into another problem. There is a file which a contains the following structure: <key>1</key> <dict>         ... </dict> <key>2</key>
25
by: Yves Glodt | last post by:
Hello, if I do this: for row in sqlsth: ________pkcolumns.append(row.strip()) ________etc without a prior:
2
by: tonci.tomic | last post by:
I have IDictionary with integers as keys and values. Suppose I want to set value for key=42 to 1 if entry doesn't exist in container. Otherwise, I want to increment value. I ended with: ...
11
by: Yves Glodt | last post by:
Hi there, I seem to be unable to find a way to appends more keys/values to the end of a dictionary... how can I do that? E.g: mydict = {'a':'1'} I need to append 'b':'2' to it to have:
6
by: Niyazi | last post by:
Hi all, What is fastest way removing duplicated value from string array using vb.net? Here is what currently I am doing but the the array contains over 16000 items. And it just do it in 10 or...
10
by: HYRY | last post by:
I have the following questions, I am using Python 2.4.2 19167152 #1 11306608 #1 1. the address of a.append and list.append is different, can I get the address of...
20
by: Seongsu Lee | last post by:
Hi, I have a dictionary with million keys. Each value in the dictionary has a list with up to thousand integers. Follow is a simple example with 5 keys. dict = {1: , 2: , 900000: , 900001:...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.