Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Hlelp clean up clumpsy code

Reply
Thread Tools

Hlelp clean up clumpsy code

 
 
It's me
Guest
Posts: n/a
 
      01-04-2005
Another newbie question.

There must be a cleaner way to do this in Python:

#### section of C looking Python code ####
a = [[1,5,2], 8, 4]
a_list = {}
i = 0
for x in a:
if isinstance(x, (int, long)):
x = [x,]
for w in [y for y in x]:
i = i + 1
a_list[w] = i
print a_list
#####

The code prints what I want but it looks so "C-like". How can I make it
more Python like?

Thanks,



 
Reply With Quote
 
 
 
 
Steven Bethard
Guest
Posts: n/a
 
      01-04-2005
It's me wrote:
> Another newbie question.
>
> There must be a cleaner way to do this in Python:
>
> #### section of C looking Python code ####
> a = [[1,5,2], 8, 4]
> a_list = {}
> i = 0
> for x in a:
> if isinstance(x, (int, long)):
> x = [x,]
> for w in [y for y in x]:
> i = i + 1
> a_list[w] = i
> print a_list
> #####
>
> The code prints what I want but it looks so "C-like". How can I make it
> more Python like?


Don't know what version of Python you're using, but if you're using 2.4
(or with a few slight modifications, with 2.3), you can write:

py> dict((item, i+1)
.... for i, item in enumerate(
.... a_sub_item
.... for a_item in a
.... for a_sub_item
.... in isinstance(a_item, (int, long)) and [a_item] or a_item))
{8: 4, 1: 1, 2: 3, 4: 5, 5: 2}

Basically, I use a generator expression to flatten your list, and then
use enumerate to count the indices instead of keeping the i variable.

Steve
 
Reply With Quote
 
 
 
 
Nick Coghlan
Guest
Posts: n/a
 
      01-04-2005
It's me wrote:
> Another newbie question.
>
> There must be a cleaner way to do this in Python:
>
> #### section of C looking Python code ####
> a = [[1,5,2], 8, 4]
> a_list = {}
> i = 0
> for x in a:
> if isinstance(x, (int, long)):
> x = [x,]
> for w in [y for y in x]:
> i = i + 1
> a_list[w] = i
> print a_list
> #####
>
> The code prints what I want but it looks so "C-like". How can I make it
> more Python like?


Firstly, calling your dictionary "a_list" is evil. . .

Secondly, explaining what you want the code to do in English is handy when
asking for help cleaning up code (since we then know which features are
deliberate, and which are accidental implementation artificacts).

If I'm reading the code correctly, you want to flatten a data structure which
may contain either substructures or actual elements.

A custom generator will do nicely:

Py> def flatten(seq):
.... for x in seq:
.... if hasattr(x, "__iter__"):
.... for y in flatten(x):
.... yield y
.... else:
.... yield x
....
Py> data = [[1,5,2],8,4]
Py> val_to_pos = {}
Py> for i, x in enumerate(flatten(data)):
.... val_to_pos[x] = i + 1
....
Py> print val_to_pos
{8: 4, 1: 1, 2: 3, 4: 5, 5: 2}

Not any shorter, but this version works correctly for any leaf elements which
don't supply __iter__ (e.g. strings), and internal elements which do (e.g.
tuples) and the depth is limited only by the maximum level of recursion. Don't
try to flatten a circular structure, though

You may not even need to write the generator, since if you have Tkinter, that
already supplies a near-equivalent function:

Py> from Tkinter import _flatten as flatten
Py> data = [[1,5,2],8,4]
Py> val_to_pos = {}
Py> for i, x in enumerate(flatten(data)):
.... val_to_pos[x] = i + 1
....
Py> print val_to_pos
{8: 4, 1: 1, 2: 3, 4: 5, 5: 2}

It even works with strings as leaf elements:

Py> data = [["abc","def",2],8,"xyz"]
Py> flatten(data)
('abc', 'def', 2, 8, 'xyz')

Cheers,
Nick.

--
Nick Coghlan | http://www.velocityreviews.com/forums/(E-Mail Removed) | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
 
Reply With Quote
 
It's me
Guest
Posts: n/a
 
      01-04-2005
Thanks, Steve and Nick.

Yes, that's what I need to do. I didn't know it's call "flattening" a list
structure but that's precisely what I needed to do.

Steve,

I am using 2.3 and so I will go with Nick's version.

Thanks to both for helping.


"Nick Coghlan" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> It's me wrote:
> > Another newbie question.
> >
> > There must be a cleaner way to do this in Python:
> >
> > #### section of C looking Python code ####
> > a = [[1,5,2], 8, 4]
> > a_list = {}
> > i = 0
> > for x in a:
> > if isinstance(x, (int, long)):
> > x = [x,]
> > for w in [y for y in x]:
> > i = i + 1
> > a_list[w] = i
> > print a_list
> > #####
> >
> > The code prints what I want but it looks so "C-like". How can I make it
> > more Python like?

>
> Firstly, calling your dictionary "a_list" is evil. . .
>
> Secondly, explaining what you want the code to do in English is handy when
> asking for help cleaning up code (since we then know which features are
> deliberate, and which are accidental implementation artificacts).
>
> If I'm reading the code correctly, you want to flatten a data structure

which
> may contain either substructures or actual elements.
>
> A custom generator will do nicely:
>
> Py> def flatten(seq):
> ... for x in seq:
> ... if hasattr(x, "__iter__"):
> ... for y in flatten(x):
> ... yield y
> ... else:
> ... yield x
> ...
> Py> data = [[1,5,2],8,4]
> Py> val_to_pos = {}
> Py> for i, x in enumerate(flatten(data)):
> ... val_to_pos[x] = i + 1
> ...
> Py> print val_to_pos
> {8: 4, 1: 1, 2: 3, 4: 5, 5: 2}
>
> Not any shorter, but this version works correctly for any leaf elements

which
> don't supply __iter__ (e.g. strings), and internal elements which do (e.g.
> tuples) and the depth is limited only by the maximum level of recursion.

Don't
> try to flatten a circular structure, though
>
> You may not even need to write the generator, since if you have Tkinter,

that
> already supplies a near-equivalent function:
>
> Py> from Tkinter import _flatten as flatten
> Py> data = [[1,5,2],8,4]
> Py> val_to_pos = {}
> Py> for i, x in enumerate(flatten(data)):
> ... val_to_pos[x] = i + 1
> ...
> Py> print val_to_pos
> {8: 4, 1: 1, 2: 3, 4: 5, 5: 2}
>
> It even works with strings as leaf elements:
>
> Py> data = [["abc","def",2],8,"xyz"]
> Py> flatten(data)
> ('abc', 'def', 2, 8, 'xyz')
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan | (E-Mail Removed) | Brisbane, Australia
> ---------------------------------------------------------------
> http://boredomandlaziness.skystorm.net



 
Reply With Quote
 
Scott David Daniels
Guest
Posts: n/a
 
      01-04-2005
Nick Coghlan wrote:
> A custom generator will do nicely:
>
> Py> def flatten(seq):
> ... for x in seq:
> ... if hasattr(x, "__iter__"):
> ... for y in flatten(x):
> ... yield y
> ... else:
> ... yield x


Avoiding LBYL gives you:
def flatten(seq):
for x in seq:
try:
for y in flatten(x):
yield y
except TypeError:
yield x

--Scott David Daniels
(E-Mail Removed)
 
Reply With Quote
 
Jeff Shannon
Guest
Posts: n/a
 
      01-04-2005
Scott David Daniels wrote:

> Nick Coghlan wrote:
>
>> A custom generator will do nicely:
>>
>> Py> def flatten(seq):
>> ... for x in seq:
>> ... if hasattr(x, "__iter__"):
>> ... for y in flatten(x):
>> ... yield y
>> ... else:
>> ... yield x

>
>
> Avoiding LBYL gives you:
> def flatten(seq):
> for x in seq:
> try:
> for y in flatten(x):
> yield y
> except TypeError:
> yield x


If I'm not mistaken, this will result in infinite recursion on
strings. 'for x in aString' will iterate over the characters in the
string, even if the string is only a single character, so "for y in
flatten('a'):" will not give a type error. You'd need to add
special-case tests to watch for this condition (and try not to be too
special-case and allow unicode objects to pass).

Nick's version works on strings (and unicode objects) because they
lack an __iter__() method, even though they follow the (older)
sequence protocol.

Jeff Shannon
Technician/Programmer
Credit International

 
Reply With Quote
 
Pierre Quentel
Guest
Posts: n/a
 
      01-04-2005
You can also do it in a more pythonic way but without generators :

# a = [[1,5,2], 8, 4]
# l = []
# for item in a:
# if isinstance(item, (int, long)):
# l.append(item)
# else:
# l+=item
# print dict([(item,i+1) for (i,item) in enumerate(l)])

It works in the same conditions as your original code (no nested lists)

A few other things :
- you don't have to type a comma for one-item lists : x = [x] works -
you probably confused with tuples where you must do x=(x,)
- instead of
# for w in [y for y in x]:
just do
# for w in x:
- for "i = i+1" there is a shortcut : i+=1 (see "l+=item" above)

Regards,
Pierre
 
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
Visual C++'s :"clean solution" doesn't clean the solution? plenty900@yahoo.com C++ 8 05-31-2008 04:57 PM
How do I clean a virus within an inbox or just clean only that infectedattachment or LOCATE AND delete just that attachment ? Vinayak Firefox 1 08-14-2006 06:19 PM
Need clean code sample for HttpWebRequest =?Utf-8?B?U3RldmU=?= ASP .Net 3 06-18-2005 08:14 AM
Clean up my Hard drive before selling it. Clean Registry? what else? baaab Computer Support 5 05-10-2005 08:30 AM
Clean code vs. efficiency Christopher Benson-Manica C++ 17 05-12-2004 07:09 PM



Advertisments