Hlelp clean up clumpsy code

Discussion in 'Python' started by It's me, Jan 4, 2005.

  1. It's me

    It's me Guest

    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,
     
    It's me, Jan 4, 2005
    #1
    1. Advertising

  2. 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
     
    Steven Bethard, Jan 4, 2005
    #2
    1. Advertising

  3. It's me

    Nick Coghlan Guest

    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 | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
     
    Nick Coghlan, Jan 4, 2005
    #3
  4. It's me

    It's me Guest

    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" <> wrote in message
    news:...
    > 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 | | Brisbane, Australia
    > ---------------------------------------------------------------
    > http://boredomandlaziness.skystorm.net
     
    It's me, Jan 4, 2005
    #4
  5. 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
     
    Scott David Daniels, Jan 4, 2005
    #5
  6. It's me

    Jeff Shannon Guest

    Re: Help clean up clumsy code

    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
     
    Jeff Shannon, Jan 4, 2005
    #6
  7. 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
     
    Pierre Quentel, Jan 4, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?U3RldmU=?=

    Need clean code sample for HttpWebRequest

    =?Utf-8?B?U3RldmU=?=, Jun 18, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    7,876
    Joerg Jooss
    Jun 18, 2005
  2. Christopher Benson-Manica

    Clean code vs. efficiency

    Christopher Benson-Manica, May 11, 2004, in forum: C++
    Replies:
    17
    Views:
    1,822
    Default User
    May 12, 2004
  3. Eric Lilja
    Replies:
    4
    Views:
    591
    Peter Koch Larsen
    Jan 8, 2005
  4. Dean Ware

    Code Clean up (refactoring?)

    Dean Ware, Mar 3, 2005, in forum: C++
    Replies:
    6
    Views:
    437
    BigBrian
    Mar 3, 2005
  5. Replies:
    8
    Views:
    544
Loading...

Share This Page