Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Filling in a tuple from unknown size list

Reply
Thread Tools

Filling in a tuple from unknown size list

 
 
boblatest
Guest
Posts: n/a
 
      11-27-2009
Hello all,

(sorry for posting from Google. I currently don't have access to my
normal nntp account.)

Here's my question: Given a list of onknown length, I'd like to be
able to do the following:

(a, b, c, d, e, f) = list

If the list has fewer items than the tuple, I'd like the remaining
tuple elements to be set to "None". If the list is longer, I'd like
the excess elements to be ignored.

The code snippet below does what I want, I was just wondering if there
was an interesting "Pythonic" way of expressing the same thing.

Thanks,
robert

def iter_inf(li, n):
for i in range(n):
if i < len(li):
r = li[i]
else:
r = None
i += 1
yield r


li = ['a', 'b', 'c']
(a, b, c, d, e) = iter_inf(li, 5)
print a, b, c, d, e
 
Reply With Quote
 
 
 
 
Peter Otten
Guest
Posts: n/a
 
      11-27-2009
boblatest wrote:

> Hello all,
>
> (sorry for posting from Google. I currently don't have access to my
> normal nntp account.)
>
> Here's my question: Given a list of onknown length, I'd like to be
> able to do the following:
>
> (a, b, c, d, e, f) = list
>
> If the list has fewer items than the tuple, I'd like the remaining
> tuple elements to be set to "None". If the list is longer, I'd like
> the excess elements to be ignored.
>
> The code snippet below does what I want, I was just wondering if there
> was an interesting "Pythonic" way of expressing the same thing.
>
> Thanks,
> robert
>
> def iter_inf(li, n):
> for i in range(n):
> if i < len(li):
> r = li[i]
> else:
> r = None
> i += 1
> yield r
>
>
> li = ['a', 'b', 'c']
> (a, b, c, d, e) = iter_inf(li, 5)
> print a, b, c, d, e


Here's an alternative implementation that works with arbitrary iterables:

>>> from itertools import chain, repeat, islice
>>> a, b, c = islice(chain("a", repeat(None)), 3)
>>> a, b, c

('a', None, None)
>>> a, b, c = islice(chain("abcde", repeat(None)), 3)
>>> a, b, c

('a', 'b', 'c')

Peter

 
Reply With Quote
 
 
 
 
Stefan Behnel
Guest
Posts: n/a
 
      11-27-2009
boblatest, 27.11.2009 13:18:
> Here's my question: Given a list of onknown length, I'd like to be
> able to do the following:
>
> (a, b, c, d, e, f) = list
>
> If the list has fewer items than the tuple, I'd like the remaining
> tuple elements to be set to "None". If the list is longer, I'd like
> the excess elements to be ignored.


What about this:

fillUp = [None] * 6
(a, b, c, d, e, f) = (list + fillUp)[:6]

Stefan
 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      11-27-2009
Peter Otten wrote:
> boblatest wrote:
>
>
>> Hello all,
>>
>> (sorry for posting from Google. I currently don't have access to my
>> normal nntp account.)
>>
>> Here's my question: Given a list of onknown length, I'd like to be
>> able to do the following:
>>
>> (a, b, c, d, e, f) = list
>>
>> If the list has fewer items than the tuple, I'd like the remaining
>> tuple elements to be set to "None". If the list is longer, I'd like
>> the excess elements to be ignored.
>>
>> The code snippet below does what I want, I was just wondering if there
>> was an interesting "Pythonic" way of expressing the same thing.
>>
>> Thanks,
>> robert
>>
>> def iter_inf(li, n):
>> for i in range(n):
>> if i < len(li):
>> r = li[i]
>> else:
>> r = None
>> i += 1
>> yield r
>>
>>
>> li = ['a', 'b', 'c']
>> (a, b, c, d, e) = iter_inf(li, 5)
>> print a, b, c, d, e
>>

>
> Here's an alternative implementation that works with arbitrary iterables:
>
>
>>>> from itertools import chain, repeat, islice
>>>> a, b, c = islice(chain("a", repeat(None)), 3)
>>>> a, b, c
>>>>

> ('a', None, None)
>
>>>> a, b, c = islice(chain("abcde", repeat(None)), 3)
>>>> a, b, c
>>>>

> ('a', 'b', 'c')
>
> Peter
>
>
>

Python 3.x has some extension to the way tuple unpacking works, and may
solve this problem (or half of it). I'm too lazy this morning to look
it up.

In Python 2.x I can't see any better way than Peter's elegant solution.
I would originally have done the chain and repeat, but followed it by
[:3] slice notation. I suspect that building an actual list would be
cheap enough, but I like the islice better.

DaveA
 
Reply With Quote
 
Jon Clements
Guest
Posts: n/a
 
      11-27-2009
On 27 Nov, 12:18, boblatest <(E-Mail Removed)> wrote:
> Hello all,
>
> (sorry for posting from Google. I currently don't have access to my
> normal nntp account.)
>
> Here's my question: Given a list of onknown length, I'd like to be
> able to do the following:
>
> (a, b, c, d, e, f) = list
>
> If the list has fewer items than the tuple, I'd like the remaining
> tuple elements to be set to "None". If the list is longer, I'd like
> the excess elements to be ignored.
>
> The code snippet below does what I want, I was just wondering if there
> was an interesting "Pythonic" way of expressing the same thing.
>
> Thanks,
> robert
>
> def iter_inf(li, n):
> * * for i in range(n):
> * * * * if i < len(li):
> * * * * * * r = li[i]
> * * * * else:
> * * * * * * r = None
> * * * * i += 1
> * * * * yield r
>
> li = ['a', 'b', 'c']
> (a, b, c, d, e) = *iter_inf(li, 5)
> print a, b, c, d, e


An alternative to Peter's itertools implementation is this
monstrosity...

import re

class name_elements:
def __init__(self, iterable, *names):
self.__names = set(names)
if len(self.__names) != len(names):
raise ValueError('names must be unique')
for it, name in zip(iterable, names):
if not re.match('[a-zA-Z][a-zA-Z0-9_]*', name):
raise ValueError("name '%s' is not valid" % name)
setattr(self, name, it)
def __getattr__(self, item):
if item not in self.__names:
raise ValueError("name '%s' not present" % item)
return self.__dict__.get(item, None)

>>> res = name_elements(['a', 'b', 'c'], 'a', 'b', 'c', 'd', 'e')
>>> print res.a, res.b, res.c, res.d, res.e

a b c None None
>>> print res.f

Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
print res.f
File "/home/jon/rubbish.py", line 10, in __getattr__
raise AttributeError("name '%s' not present" % item)
AttributeError: name 'f' not present

It removes the need to know the number being unpacked (I can see this
being overlooked) and the variable names could come from a list
instead of being named in code. Asking for a name that doesn't exist
is an exception, while all other values default to None.

However, it's not totally identical to unpacking... (and most likely
slower)

I s'pose namedtuple could also be abused in a similar fashion.

Or, if you don't mind []'ing:
>>> dd = defaultdict(lambda: None)
>>> dd.update(zip(['a', 'b', 'c'], range(5)))
>>> print dd['a'], dd['c'], dd['blah']

0 2 None

Is it obvious I'm trying to avoid doing proper work!?

Cheers,
Jon.

 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      11-27-2009
On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:

> Here's my question: Given a list of onknown length, I'd like to be able
> to do the following:
>
> (a, b, c, d, e, f) = list
>
> If the list has fewer items than the tuple, I'd like the remaining tuple
> elements to be set to "None". If the list is longer, I'd like the excess
> elements to be ignored.


I'd call that a code-smell. If I saw that in code, I'd think long and
hard about why it was there and if I could eliminate the names a...f and
just work directly with the list.

But if you really do need it, I think the simplest and best way is to use
the technique Stefan suggested:

a, b, c, d, e, f = (list + [None]*6)[:6]

provided list is short. If you fear that list might be huge and copying
it will be prohibitively expensive:

a, b, c, d, e, f = (list[:6] + [None]*6)[:6]



--
Steven
 
Reply With Quote
 
Mel
Guest
Posts: n/a
 
      11-27-2009
Steven D'Aprano wrote:
> On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:
>> Here's my question: Given a list of onknown length, I'd like to be able
>> to do the following:
>>
>> (a, b, c, d, e, f) = list
>>
>> If the list has fewer items than the tuple, I'd like the remaining tuple
>> elements to be set to "None". If the list is longer, I'd like the excess
>> elements to be ignored.


> I'd call that a code-smell. If I saw that in code, I'd think long and
> hard about why it was there and if I could eliminate the names a...f and
> just work directly with the list.


It's a common enough thing at the boundaries of your program, letting user
input in through the gates, as it were. Deeper in, I agree; that stuff
should have been dealt with at the gates.

Mel.

 
Reply With Quote
 
Stefan Behnel
Guest
Posts: n/a
 
      11-27-2009
Mel, 27.11.2009 18:47:
> Steven D'Aprano wrote:
>> On Fri, 27 Nov 2009 04:18:08 -0800, boblatest wrote:
>>> Here's my question: Given a list of onknown length, I'd like to be able
>>> to do the following:
>>>
>>> (a, b, c, d, e, f) = list
>>>
>>> If the list has fewer items than the tuple, I'd like the remaining tuple
>>> elements to be set to "None". If the list is longer, I'd like the excess
>>> elements to be ignored.

>
>> I'd call that a code-smell. If I saw that in code, I'd think long and
>> hard about why it was there and if I could eliminate the names a...f and
>> just work directly with the list.

>
> It's a common enough thing at the boundaries of your program, letting user
> input in through the gates, as it were. Deeper in, I agree; that stuff
> should have been dealt with at the gates.


But that may have a code smell on it, too. In most cases, when users
provide excessive arguments that the program would ignore, that's best
treated as an error.

Stefan
 
Reply With Quote
 
John Machin
Guest
Posts: n/a
 
      11-28-2009
On Nov 27, 11:18*pm, boblatest <(E-Mail Removed)> wrote:
> Hello all,
>
> (sorry for posting from Google. I currently don't have access to my
> normal nntp account.)
>
> Here's my question: Given a list of onknown length, I'd like to be
> able to do the following:
>
> (a, b, c, d, e, f) = list
>
> If the list has fewer items than the tuple, I'd like the remaining
> tuple elements to be set to "None". If the list is longer, I'd like
> the excess elements to be ignored.


WRONG -- sweeping excess input under the carpet is a nasssssty perlish
trick.
 
Reply With Quote
 
Ned Deily
Guest
Posts: n/a
 
      11-29-2009
In article
<da776a8c0911290142o8ddce42n4825188bc5e23c50@mail. gmail.com>,
inhahe <(E-Mail Removed)> wrote:
> maybe that thing in python 3 that someone mentioned is the answer, but
> otherwise i always think Python should admit something like this:
>
> a, b, c, *d = list
>
> i.e. if list were [1,2,3,4,5], you'd get a=1, b=2, c=3, d=[4, 5]


Extended iterable unpacking (http://www.python.org/dev/peps/pep-3132/)
is implemented in python 3.

$ python3
Python 3.1.1 (r311:74543, Aug 24 2009, 18:44:04)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a, b, c, *d = [1,2,3,4,5]
>>> d

[4, 5]

--
Ned Deily,
http://www.velocityreviews.com/forums/(E-Mail Removed)

 
Reply With Quote
 
 
 
Reply

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 Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Creating A Tuple From A List, Adding To Tuple As You Do Jeff Nyman Python 8 06-05-2008 09:04 PM
List to Tuple and Tuple to List? Davy Python 3 11-07-2007 06:19 PM
Easily convert unicode tuple to python string tuple??? Michal Mikolajczyk Python 1 04-20-2004 08:37 PM
Re: Easily convert unicode tuple to python string tuple??? Jeff Epler Python 0 04-20-2004 03:36 PM
Re: Easily convert unicode tuple to python string tuple??? Bill Scherer Python 0 04-20-2004 03:34 PM



Advertisments