0

Given nested list: [1, (1, 2), [3, 4], {5: 6}], write a program that will make the element of these element as a key and position of these elements as a value.

My code: (read comments)

#!/usr/bin/python
def code(lst):
    '''
      lst: A nested hybrid list!
      type: list

      returns: linear dict
    '''
    d = {}
    try:
        for i, l in enumerate(lst):
            if isinstance(l, list): # I know lists are unhashable
                for e in l:
                    d[e] = i
            elif isinstance(l, dict): # I know dicts are unhashable
                for e in l.items():
                    d[e[0]] = i
                    d[e[1]] = i
            else:
                d[l] = i    
    except TypeError, e:
        print "invalid key!"
        print "Check your nested values"
    except Exception, e: # One should catch every possible exception else code fault
        printf "My Code fault!"
    return d

And it is working!

Call:

print code([1, (1, 2), {3: 4}, [5, 6]])

output:

{(1, 2): 1, 1: 0, 3: 2, 4: 2, 5: 3, 6: 3}

I am Python learner, I written this code with assumption that key fetched from list will be unique e.g. [1, 2, [1, 2]] is an invalid input.

[Question]

  1. I just want to know: How can I improve my code further, so it become small in length and fast?
  2. I learn from "Apress Beginning Python" that one should avoid use of isinstance(). So is there any other way to write this code?

  3. Can you suggest me how to improve code for arbitrary nested and hybrid e.g.

    #   0     1            2        3         <-- index
       [1, (1, 2), {3: [4, 5]}, [{6: 7} , 8]]
    

    output:

      {1: 0, (1, 2): 1, 3: 2, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3}  
     #    ^          ^     ^     ^     ^     ^     ^     ^ 
     #        index in outer list             
    

    I can handle nested at two level but nested at any level is not possible for me, please suggest a trick. A suggestion would be enough but should be Pythonic.
    (3rd question is main problem for which I posted this question)

Edit:

As pointed @tcaswell:

How would you want to deal with [1, {1: 2}]? 1 should be mapped to both 0 and 1 under your current rules.

For simplicity I am assuming this input is invalid. "assumption that key fetched from list will be unique"

tmj
  • 1,750
  • 2
  • 19
  • 34
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208

3 Answers3

1

one should avoid use of isinstance(). So is there any other way to write this code?

I've rarely seen such arbitrary heterogeny in data except in textbook exercises therefore I agree with the recommendation that you avoid isinstance as much as possible. So the general answer is: if you find yourself coping with crazy structures, the code that gave it to you is poorly designed and you should fix that. Put another way, the desired output of your call to code() is {(1, 2): 1, 1: 0, 3: 2, 4: 2, 5: 3, 6: 3} what could you do with that value that doesn't require more code at least as uselessly complicated as code() itself?

To translate this problem to C terms: how often do you have to handle with an array of pointers to unions? Almost never, and it is a pain when you do because a union always needs to carry a type indicator along with it so you ensure access to the proper union member.

One should catch every possible exception else code fault

This is wrong; you want the code to fault because it a great way to find bugs. Following PEP-20:

Errors should never pass silently.
Unless explicitly silenced.

You should never catch exceptions that you do not know how to handle, and printing an error message rarely counts as properly handling an exception. An old answer of mine addresses this common error more fully.

Community
  • 1
  • 1
msw
  • 42,753
  • 9
  • 87
  • 112
1

I can't understand something you wrote:

I written this code with assumption that key fetched from list will be unique e.g. [1, 2, [1, 2]] is an invalid input

but then your "valid" input is this:

[1, (1, 2), {3: 4}, [5, 6]]

where the number "1" is repeated...

Anyway to answer your question. I'd write a recursive method (this should address arbitrary nested items) with some more "entry" in your if..else statement. For example something like this:

def foo(a):
    x = {}
    for i,b in enumerate(a):
        if isinstance(b,list):
            for k in b:
                x[k]=i
        elif isinstance(b,dict):
            for k in b.items():
                x[k[0]]=i
                x[k[1]]=i
        elif isinstance(b,set):
            for k in b:
                x[k]=i
        elif isinstance(b,tuple):
            for k in b:
                x[k]=i
        else:
            x[b]=i
    return x

foo([1,(2,3),{4,5},[6,7]])
{1: 0, 2: 1, 3: 1, 4: 2, 5: 2, 6: 3, 7: 3}

While I can't answer you about how fast is isinstance function, but AFAIK it's the only way to detect a type.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Alberto
  • 718
  • 4
  • 20
  • 1
    try and see what the OP is expecting as answer. Tuples are handled specially in the question. – tmj Sep 24 '13 at 17:04
  • Thanks for your answer. I included `1` in tuple because can tuple be a key of dict. What I say input list give unique keys. --btw I can't see recursive call of `foo()` in your function. and yes here `type()` is an alternate of `isinstance`. – Grijesh Chauhan Sep 24 '13 at 17:29
1
bigList = [1, (1, 2), {(3,9): [4, 5]}, [{6: 7} , 8]]
linear_dict = dict()

def nestedList(l, index = None, break_tuple = False):
    for count, item in enumerate(l):
        if type(item) is list:
            nestedList(item, index if index else count)
        elif type(item) is dict:
            nestedList(item.iteritems(), index if index else count, True)
        elif type(item) is tuple and break_tuple:
            nestedList(list(item), index)
        else:
            linear_dict[item] = index if index else count

nestedList(bigList)
print linear_dict

{(1, 2): 1, 1: 0, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, (3, 9): 2}

This was more of a problem on recursion rather than lists, tuples and dictionaries per say.

About isinstance() and type(), read these:

  1. Differences between isinstance() and type() in python
  2. What is the best (idiomatic) way to check the type of a Python variable?

Although, the things mentioned here do not apply much to your question, because as msw mentioned, it seems more like a textbook question. Apart from that, the answers in the link contain some good advice.

Basic rule of shortening the code is to write it down first, quick and dirty, and then see what can you replace by a shorter code snippet which achieves the same thing.

Community
  • 1
  • 1
tmj
  • 1,750
  • 2
  • 19
  • 34