By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
444,035 Members | 1,408 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 444,035 IT Pros & Developers. It's quick & easy.

default value in a list

P: n/a
TB
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:
a, b, c = (line.split(':'))

if line could have less than three fields?

Thanks,
TB

Jul 18 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
What do you want put into the "missing" variables?
I'll assume None. Something like following
works:

values=line.split(':')
try: a=values.pop(0)
except IndexError: a=None
try: b=values.pop(0)
except IndexError: b=None
try: c=values.pop(0)
except IndexError: c=None
Larry Bates

TB wrote:
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:

a, b, c = (line.split(':'))


if line could have less than three fields?

Thanks,
TB

Jul 18 '05 #2

P: n/a
TB wrote:
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:

a, b, c = (line.split(':'))
if line could have less than three fields?

l = line.split(':')

l is a list, whose length will be one more than the number of colons in
the line.

You can access the elements of the list using a[0], a[2], and so on. For
example:
line = "This:is:a:sample:line"
l = line.split(':')
l ['This', 'is', 'a', 'sample', 'line'] for w in l: ... print w
...
This
is
a
sample
line len(l) 5


regards
Steve
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/
Holden Web LLC +1 703 861 4237 +1 800 494 3119
Jul 18 '05 #3

P: n/a
"TB" <tb******@yahoo.com> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:
a, b, c = (line.split(':'))

if line could have less than three fields?

Thanks,
TB

I asked a very similar question a few weeks ago, and from the various
suggestions, I came up with this:

line = "AAAA:BBB"
expand = lambda lst,default,minlen : (lst + [default]*minlen)[0:minlen]
a,b,c = expand( line.split(":"), "", 3 )
print a
print b
print c

-- Paul
Jul 18 '05 #4

P: n/a
Paul McGuire wrote:
expand = lambda lst,default,minlen : (lst + [default]*minlen)[0:minlen]


Or if you're afraid of lambda like me:

def expand(lst,default,minlen):return (lst + [default]*minlen)[0:minlen]

or perhaps more readably:

def expand(lst, default, minlen):
return (lst + [default]*minlen)[0:minlen]

No need for an anonymous function when you're naming it. ;)

Steve
Jul 18 '05 #5

P: n/a
TB wrote:
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:

a, b, c = (line.split(':'))
if line could have less than three fields?


(Note that you're actually assigning to a group of local variables,
via tuple unpacking, not assigning to a list...)

One could also do something like this:
l = "a:b:c".split(':')
a, b, c, d, e = l + ([None] * (5 - len(l)))
print (a, b, c, d, e) ('a', 'b', 'c', None, None)
Personally, though, I can't help but think that, if you're not certain
how many fields are in a string, then splitting it into independent
variables (rather than, say, a list or dict) *cannot* be an elegant
solution. If the fields deserve independent names, then they must
have a definite (and distinct) meaning; if they have a distinct
meaning (as opposed to being a series of similar items, in which case
you should keep them in a list), then which field is it that's
missing? Are you sure it's *always* the last fields? This feels to
me like the wrong solution to any problem.

Hm, speaking of fields makes me think of classes.
class LineObj: .... def __init__(self, a=None, b=None, c=None, d=None, e=None):
.... self.a = a
.... self.b = b
.... self.c = c
.... self.d = d
.... self.e = e
.... l = "a:b:c".split(':')
o = LineObj(*l)
o.__dict__ {'a': 'a', 'c': 'c', 'b': 'b', 'e': None, 'd': None}


This is a bit more likely to be meaningful, in that there's almost
certainly some logical connection between the fields of the line
you're splitting and keeping them as a class demonstrates that
connection, but it still seems a bit smelly to me.

Jeff Shannon
Technician/Programmer
Credit International
Jul 18 '05 #6

P: n/a
Paul McGuire wrote:
I asked a very similar question a few weeks ago, and from the various
suggestions, I came up with this:

expand = lambda lst,default,minlen : (lst + [default]*minlen)[0:minlen]


I wouldn't trust whoever suggested that. if you want a function, use a function:

def expand(seq, default, minlen):
return (seq + [default]*minlen)[:minlen]

</F>

Jul 18 '05 #7

P: n/a
TB <tb******@yahoo.com> wrote:
Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:
a, b, c = (line.split(':'))

if line could have less than three fields?


import itertools as it

a, b, c = it.islice(
it.chain(
line.split(':'),
it.repeat(some_default),
),
3)

I find itertools-based solutions to be generally quite elegant.

This one assumes you want to assign some_default to variables in the LHS
target beyond the length of the RHS list. If what you want is to repeat
the RHS list over and over instead, this simplifies the first argument
of islice:

a, b, c = it.islice(it.cycle(line.split(':')), 3)

Of course, you can always choose to write your own generator instead of
building it up with itertools. itertools solutions tend to be faster,
and I think it's good to get familiar with that precious modules, but
without such familiarity many readers may find a specially coded
generator easier to follow. E.g.:

def pad_with_default(N, iterable, default=None):
it = iter(iterable)
for x in it:
if N<=0: break
yield x
N -= 1
while N>0:
yield default
N -= 1

a, b, c = pad_with_default(3, line.split(':'))
The itertools-based solution hinges on a higher level of abstraction,
glueing and tweaking iterators as "atoms"; the innards of a custom coded
generator tend to be programmed at a lower level of abstraction,
reasoning in item-by-item mode. There are pluses and minuses to each
approach; I think in the long range higher abstraction pays off, so it's
worth the investment to train yourself to use itertools.
In the Python Cookbook new 2nd edition, due out in a couple months,
we've added a whole new chapter about iterators and generators, since
it's such a major subfield in today's Python (as evidenced by the wealth
of recipes submitted to Activestate's online cookbook sites on the
subject). A couple of recipes have do with multiple unpacking
assignment -- one of them, in particular, is an evil hack which peers
into the caller's bytecode to find out how many items are on the LHS, so
you don't have to pass that '3' explicitly. I guess that might be
considered "elegant", for suitably contorted meanings of "elegant"...
it's on the site, too, but I don't have the URL at hand. It's
instructive, anyway, but I wouldn't suggest actually using it in any
kind of production code...
Alex
Jul 18 '05 #8

P: n/a
Paul McGuire wrote:
Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:
>>> a, b, c = (line.split(':')) if line could have less than three fields?

I asked a very similar question a few weeks ago, and from the various
suggestions, I came up with this:

line = "AAAA:BBB"
expand = lambda lst,default,minlen : (lst + [default]*minlen)[0:minlen]
a,b,c = expand( line.split(":"), "", 3 )


Here is an expand() variant that is not restricted to lists but works with
arbitrary iterables:

from itertools import chain, repeat, islice

def expand(iterable, length, default=None):
return islice(chain(iterable, repeat(default)), length)

Peter


Jul 18 '05 #9

P: n/a
Peter Otten wrote:
Paul McGuire wrote:
Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:

>>> a, b, c = (line.split(':'))
if line could have less than three fields?
I asked a very similar question a few weeks ago, and from the various
suggestions, I came up with this:

line = "AAAA:BBB"
expand = lambda lst,default,minlen : (lst + [default]*minlen)[0:minlen]
a,b,c = expand( line.split(":"), "", 3 )


Here is an expand() variant that is not restricted to lists but works with
arbitrary iterables:

from itertools import chain, repeat, islice

def expand(iterable, length, default=None):
return islice(chain(iterable, repeat(default)), length)


Also nice, IMHO, is allowing individual defaults for different positions in
the tuple:
def expand(items, defaults): .... if len(items) >= len(defaults):
.... return items[:len(defaults)]
.... return items + defaults[len(items):]
.... expand((1, 2, 3), (10, 20, 30, 40)) (1, 2, 3, 40) expand((1, 2, 3), (10, 20))

(1, 2)

Peter

Jul 18 '05 #10

P: n/a
TB <tb******@yahoo.com> wrote:
Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:
a, b, c = (line.split(':'))

if line could have less than three fields?


You could use this old trick...

a, b, c = (line+"::").split(':')[:3]

Or this version if you want something other than "" as the default

a, b, b = (line.split(':') + 3*[None])[:3]

BTW This is a feature I miss from perl...

--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Jul 18 '05 #11

P: n/a
Nick Craig-Wood <ni**@craig-wood.com> wrote:
...
Or this version if you want something other than "" as the default

a, b, b = (line.split(':') + 3*[None])[:3]
Either you mean a, b, c -- or you're being subtler than I'm grasping.

BTW This is a feature I miss from perl...


Hmmm, I understand missing the ``and all the rest goes here'' feature
(I'd really love it if the rejected
a, b, *c = whatever
suggestion had gone through, ah well), but I'm not sure what exactly
you'd like to borrow instead -- blissfully by now I've forgotten a lot
of the perl I used to know... care to clarify?
Alex
Jul 18 '05 #12

P: n/a
On Fri, 21 Jan 2005 17:04:11 -0800, Jeff Shannon <je**@ccvcorp.com> wrote:
TB wrote:
Hi,

Is there an elegant way to assign to a list from a list of unknown
size? For example, how could you do something like:

> a, b, c = (line.split(':'))
if line could have less than three fields?


(Note that you're actually assigning to a group of local variables,
via tuple unpacking, not assigning to a list...)

One could also do something like this:
l = "a:b:c".split(':')
a, b, c, d, e = l + ([None] * (5 - len(l)))
print (a, b, c, d, e)('a', 'b', 'c', None, None)
Or a, b, c, d, e = ('a:b:c'.split(':')+[None]*4)[:5]
print (a, b, c, d, e) ('a', 'b', 'c', None, None)

You could even be profligate and use *5 in place of that *4,
if that makes an easier idiom ;-)

Works if there's too many too:
a, b = ('a:b:c'.split(':')+[None]*2)[:2]
print (a, b) ('a', 'b')

Personally, though, I can't help but think that, if you're not certain
how many fields are in a string, then splitting it into independent
variables (rather than, say, a list or dict) *cannot* be an elegant
solution. If the fields deserve independent names, then they must
have a definite (and distinct) meaning; if they have a distinct
meaning (as opposed to being a series of similar items, in which case
you should keep them in a list), then which field is it that's
missing? Are you sure it's *always* the last fields? This feels to
me like the wrong solution to any problem.

Hm, speaking of fields makes me think of classes.
class LineObj:... def __init__(self, a=None, b=None, c=None, d=None, e=None):
... self.a = a
... self.b = b
... self.c = c
... self.d = d
... self.e = e
... l = "a:b:c".split(':')
o = LineObj(*l)
o.__dict__{'a': 'a', 'c': 'c', 'b': 'b', 'e': None, 'd': None}


This is a bit more likely to be meaningful, in that there's almost
certainly some logical connection between the fields of the line
you're splitting and keeping them as a class demonstrates that
connection, but it still seems a bit smelly to me.

That gives me an idea:
def foo(a=None, b=None, c=None, d=None, e=None, *ignore): ... return a, b, c, d, e
... a, b, c, d, e = foo(*'a:b:c'.split(':'))
print (a, b, c, d, e) ('a', 'b', 'c', None, None)

But then, might as well do:
def bar(nreq, *args): ... if nreq <= len(args): return args[:nreq]
... return args+ (nreq-len(args))*(None,)
... a, b, c, d, e = bar(5, *'a:b:c'.split(':'))
print (a, b, c, d, e) ('a', 'b', 'c', None, None) a, b = bar(2, *'a:b:c'.split(':'))
print (a, b) ('a', 'b') a, b, c = bar(3, *'a:b:c'.split(':'))
print (a, b, c) ('a', 'b', 'c')

But usually, I would like n + tail, where I know n is a safe bet, e.g.,
def ntail(n, *args): ... return args[:n]+(args[n:],)
... a, b, t = ntail(2, *'a:b:c:d:e'.split(':'))
print (a, b, t) ('a', 'b', ('c', 'd', 'e')) a, b, t = ntail(2, *'a:b'.split(':'))
print (a, b, t)

('a', 'b', ())
People have asked to be able to spell that as

a, b, *t = 'a:b:c:d:e'.split(':')

Regards,
Bengt Richter
Jul 18 '05 #13

P: n/a
TB
Thanks very much for all the responses. They were useful to me and
I'll probably refer back to them again in the future.

TB

Jul 18 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.