Velocity Reviews > How to get an item from a simple set?

# How to get an item from a simple set?

Pete Forman
Guest
Posts: n/a

 11-24-2004
I have a set that contains one item. What is the best way of getting
at that item? Using pop() empties the set. Here is what I've tried.

Python 2.3.4 (#1, Jun 13 2004, 11:21:03)
[GCC 3.3.1 (cygming special)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from sets import Set
>>> s = Set(['foo'])
>>> s.copy().pop()

'foo'
>>> [x for x in s][0]

'foo'
>>> s[0]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unindexable object

--
Pete Forman -./\.- Disclaimer: This post is originated
WesternGeco -./\.- by myself and does not represent
http://www.velocityreviews.com/forums/(E-Mail Removed) -./\.- opinion of Schlumberger, Baker
http://petef.port5.com -./\.- Hughes or their divisions.

Steven Bethard
Guest
Posts: n/a

 11-24-2004
Pete Forman wrote:
> I have a set that contains one item. What is the best way of getting
> at that item? Using pop() empties the set. Here is what I've tried.

This is what tuple unpacking is for:

>>> s = set(['foo'])
>>> item, = s
>>> item

'foo'
>>> [item] = s
>>> item

'foo'

It's up to you whether you like the tuple or list syntax better. =)

Steve

Skip Montanaro
Guest
Posts: n/a

 11-24-2004

Pete> I have a set that contains one item. What is the best way of
Pete> getting at that item? Using pop() empties the set.

Do you want to enumerate all the items in the set? If so:

for elt in s:
print elt

If you just want to grab one arbitrary (though not random) item from the
set, try:

elt = iter(s).next()

Note that repeating this operation will always return the same item:

>>> s

set(['jkl', 'foo', 'abc', 'def', 'ghi'])
>>> iter(s).next()

'jkl'
>>> iter(s).next()

'jkl'
>>> iter(s).next()

'jkl'
>>> iter(s).next()

'jkl'

Skip

Pete Forman
Guest
Posts: n/a

 11-24-2004
Skip Montanaro <(E-Mail Removed)> writes:

> Pete> I have a set that contains one item. What is the best way of
> Pete> getting at that item? Using pop() empties the set.
>
> If you just want to grab one arbitrary (though not random) item from the
> set, try:
>
> elt = iter(s).next()

I actually wanted to append the single item to a string, Steven's
solutions work for assignment.

So this looks like my best bet. I'll probably use join instead of +=
in my code.

>>> line = 'bar '
>>> line += iter(s).next()
>>> line

'bar foo'

--
Pete Forman -./\.- Disclaimer: This post is originated
WesternGeco -./\.- by myself and does not represent
(E-Mail Removed) -./\.- opinion of Schlumberger, Baker
http://petef.port5.com -./\.- Hughes or their divisions.

Steven Bethard
Guest
Posts: n/a

 11-24-2004
Pete Forman wrote:
> I actually wanted to append the single item to a string, Steven's
> solutions work for assignment.

[snip]
>>>>line = 'bar '
>>>>line += iter(s).next()
>>>>line

> 'bar foo'

Yeah, using the assignment's an extra line:

>>> line_list = ['bar ']
>>> item, = s
>>> line_list.append(item)
>>> ''.join(line_list)

'bar foo'

I still tend to write the extra line in cases like this -- it guarantees
that the set is really the size that I think it is, where the
iter(s).next() solution will not raise an exception if the set is
actually larger.

Steve

Pete Forman
Guest
Posts: n/a

 11-24-2004
Steven Bethard <(E-Mail Removed)> writes:

> I still tend to write the extra line in cases like this -- it
> guarantees that the set is really the size that I think it is, where
> the iter(s).next() solution will not raise an exception if the set
> is actually larger.

The preceding line in my code is
if len(s) == 1:

--
Pete Forman -./\.- Disclaimer: This post is originated
WesternGeco -./\.- by myself and does not represent
(E-Mail Removed) -./\.- opinion of Schlumberger, Baker
http://petef.port5.com -./\.- Hughes or their divisions.

Bengt Richter
Guest
Posts: n/a

 11-24-2004
On Wed, 24 Nov 2004 09:46:50 -0600, Skip Montanaro <(E-Mail Removed)> wrote:

>
> Pete> I have a set that contains one item. What is the best way of
> Pete> getting at that item? Using pop() empties the set.
>
>Do you want to enumerate all the items in the set? If so:
>
> for elt in s:
> print elt
>
>If you just want to grab one arbitrary (though not random) item from the
>set, try:
>
> elt = iter(s).next()
>
>Note that repeating this operation will always return the same item:
>
> >>> s

> set(['jkl', 'foo', 'abc', 'def', 'ghi'])
> >>> iter(s).next()

> 'jkl'
> >>> iter(s).next()

> 'jkl'
> >>> iter(s).next()

> 'jkl'
> >>> iter(s).next()

> 'jkl'
>

Lest someone else not realize that the operation you are repeating includes creating
a fresh initialized iterator each time, and you're just doing it as a way to grab one element:

>>> s = set(['jkl', 'foo', 'abc', 'def', 'ghi'])
>>> it = iter(s)
>>> it.next()

'jkl'
>>> it.next()

'foo'
>>> it.next()

'abc'
>>> it.next()

'def'
>>> it.next()

'ghi'
>>> it.next()

Traceback (most recent call last):
File "<stdin>", line 1, in ?
StopIteration

Regards,
Bengt Richter

Bengt Richter
Guest
Posts: n/a

 11-24-2004
On Wed, 24 Nov 2004 15:40:30 GMT, Steven Bethard <(E-Mail Removed)> wrote:

>Pete Forman wrote:
>> I have a set that contains one item. What is the best way of getting
>> at that item? Using pop() empties the set. Here is what I've tried.

>
>This is what tuple unpacking is for:
>
> >>> s = set(['foo'])
> >>> item, = s
> >>> item

>'foo'
> >>> [item] = s
> >>> item

>'foo'
>
>It's up to you whether you like the tuple or list syntax better. =)
>

Thanks. I didn't realize a list format could be used to specify target names
like that. My intial reaction is a bendy feeling in my list expression syntax
recognizer, though. I'm not sure I like that on the left hand side.
It feels too much like __setitem__ on some implied object. The tuple syntax
on the left hand side is only for unpacking (unless you want to imagine invoking
an implied unnamed function, but that's a stretch IMO), so it doesn't trigger
that near-miss syntax recognition feeling.

Regards,
Bengt Richter

Steven Bethard
Guest
Posts: n/a

 11-24-2004
Pete Forman wrote:
> Steven Bethard <(E-Mail Removed)> writes:
>
>
>>I still tend to write the extra line in cases like this -- it
>>guarantees that the set is really the size that I think it is, where
>>the iter(s).next() solution will not raise an exception if the set
>>is actually larger.

>
>
> The preceding line in my code is
> if len(s) == 1:
>

So is this just one branch of a case statement? What do you do in the
case that len(s) != 1? And which one happens more often?

If I have two possible unpackings of an iterable and I know one is much
more common than the other, I often do something like:

try:
x, y = s # more common unpacking
except ValueError:
[x], y = s, None # less common ('exceptional') unpacking

This is a reasonable pattern if your code really does favor one branch
substantially over the other. But dont' take my word for it. Here's
what timeit says:

----- test.py ----
def test_cond(*args):
if len(args) == 1:
[x], y = args, None
elif len(args) == 2:
x, y = args
else:
raise ValueError('wrong number of arguments')

def test_try(*args):
try:
x, y = args
except ValueError:
[x], y = args, None

def test(fn, single_times, double_times):
for _ in range(single_times):
fn(1)
for _ in range(double_times):
fn(0, 1)

---- command prompt ----
>python -m timeit -s "import test" "test.test(test.test_cond, 10, 10)"

10000 loops, best of 3: 26.7 usec per loop

>python -m timeit -s "import test" "test.test(test.test_try, 10, 10)"

10000 loops, best of 3: 116 usec per loop

>python -m timeit -s "import test" "test.test(test.test_cond, 1, 100)"

10000 loops, best of 3: 132 usec per loop

>python -m timeit -s "import test" "test.test(test.test_try, 1, 100)"

10000 loops, best of 3: 99.8 usec per loop

As you can see, when the try/except block is slower when the two
branches get traversed approximately equally, but faster when one branch
is substantially favored over the other.

Steve

Steven Bethard
Guest
Posts: n/a

 11-24-2004
Bengt Richter wrote:
> On Wed, 24 Nov 2004 15:40:30 GMT, Steven Bethard <(E-Mail Removed)> wrote:
>>
>>>>>[item] = s
>>>>>item

>>
>>'foo'
>>
>>It's up to you whether you like the tuple or list syntax better. =)
>>

>
> Thanks. I didn't realize a list format could be used to specify target names
> like that. My intial reaction is a bendy feeling in my list expression syntax
> recognizer, though. I'm not sure I like that on the left hand side.
> It feels too much like __setitem__ on some implied object. The tuple syntax
> on the left hand side is only for unpacking (unless you want to imagine invoking
> an implied unnamed function, but that's a stretch IMO), so it doesn't trigger
> that near-miss syntax recognition feeling.

Yeah, I almost always prefer the tuple (comma) syntax, but occasionally
I find the list syntax clearer, if, for example, I'm unpacking a nested
single-item list:

>>> t

[['abcd'], 1, 2]
>>> (x,), y, z = t
>>> x, y, z

('abcd', 1, 2)

The ,), in the tuple-only unpacking makes me uncomfortable for some
reason. I feel marginally more comfortable with:

>>> [x], y, z = t
>>> x, y, z

('abcd', 1, 2)

Of course, I generally feel uncomfortable if I have a weird unpacking
thing like this anyway. It pretty much only comes up for me when I want
to assign some default values in one branch of a try/except or if/else
statement, e.g.

try:
x, y = s
except ValueError:
[x], y = s, None

Steve

 Thread Tools

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post Edward A. Falk C Programming 1 04-04-2013 08:07 PM Johannes Zellner Python 1 01-17-2006 01:09 AM tj.tzavaras@gmail.com HTML 2 04-28-2005 03:42 PM ssoss ASP .Net 2 09-18-2003 11:35 PM root C Programming 2 08-21-2003 07:07 PM

Advertisments