1

I am trying to reverse dictionary. I have a dictionary called person_to_networks. This function works fine, but my reverse function gives me an error. It says 'function' object is not subscriptable. The text file contains person's name, networks and friends' names. Here is the text

def person_to_networks(profiles_file):
    """
    (file open for reading) -> dic of {str: list of str}

    """
    # initialize data to be processed

This is invert function :

def invert_networks_dict(person_to_networks):
     """
    (dict of {str: list of str}) -> dict of {str: list of str}
    Return a "network to people" dictionary based on the given 
    "person to networks" dictionary.

    """

I appreciate your help in advance!

doniyor
  • 36,596
  • 57
  • 175
  • 260
user3477470
  • 53
  • 1
  • 3
  • 9
  • 1
    I'm not sure if this is what you're asking but in Python 2.7 or later you can reverse any arbitrary dict (with hashable values) using `d = {v:k for k,v in d.items()}`. – Two-Bit Alchemist Mar 30 '14 at 23:05
  • @Two-Bit Alchemist It appears from the comments and usage that v is a list and that what he wants to do is create an individual key from each element in the list and create a list containing the k's that had that element in the original dictionary. As a result, the straight inversion would not work. – sabbahillel Mar 31 '14 at 02:59
  • `{v:k for k, values in d.items() for v in values}` although that wouldn't deal with the same key getting overwritten multiple times if it appeared multiple times in the `values` lists. – Two-Bit Alchemist Mar 31 '14 at 12:56

2 Answers2

0

It looks like you are passing the person_to_network() function object as an argument to the invert_networks_dict() function. You are then treating the person_to_network variable inside the local scope of the function as both a dictionary object and a callable function object.

Consequently you are raising an object not subscriptable exception, as functions are not subscriptable in Python (e.g. they do not support the __getitem__() method like dictionaries do). More on the what it means to be subscriptable here

So I expect what you want to do is assign the dictionary returned from calling the person_to_network() function into a new variable.

def invert_networks_dict(person_to_networks):
    """
    (dict of {str: list of str}) -> dict of {str: list of str}
    Return a "network to people" dictionary based on the given 
    'person to networks' dictionary.
    """

    networks_to_person = {}
    person_to_network_dict = person_to_networks(profiles_file)
    for person in person_to_network_dict:
        networks = person_to_networks_dict[person]
        # etc

Note you don't need to pass the person_to_networks() function object to the invert_networks_dict() function. If Python doesn't find a variable match in the local function scope, it looks into any enclosing functions and then the global scope to find a match.

>>> def foo():
        print "foo"

>>> def bar():
        foo()

>>> bar()
foo

More on namespaces and scoping rules here.

Community
  • 1
  • 1
dannymilsom
  • 2,386
  • 1
  • 18
  • 19
  • Thanks for your comments, but I get an error on line networks= persom_to_networks[person]. It says function object is not subscriptable.. how can I fix this problem..? – user3477470 Mar 31 '14 at 00:06
0

Your first error is that you use the function person_to_networks as the dictionary name as well. You should give it a different name. Currently, when it is used as an argument, python sees that it has been defined as a function and tries to use it as such. I have changed the name below from person_to_networks (which is the name of the function) to person_dict to show what needs to be done for that. In that case you would call the two functions separately and pass the resulting dictionary in to the invert function. If you want to just call the invert function, pass in the pointer to the person_to_networks() function and call it to set the dictionary value, then use the dictionary value.

Note that the way you have it makes person the dictionary and not the key from that dictionary.

Note the line that I have put the ** indicator around below. This will reset the networks_to_person[networks] value so that you wipe out the previous value. The if will then append the same value to the dictionary. Also, you should make the initial value [person] so that future values can be appended. Also you may want to check that you have not already put person in that value of networks.

def invert_networks_dict(person_to_networks):
  """
  (dict of {str: list of str}) -> dict of {str: list of str}
  Return a "network to people" dictionary based on the given 
  "person to networks" dictionary.

  """
  networks_to_person = {}
  person_dict = person_to_networks(profiles_file)
  for person in person_dict:
    networks = person_dict[person] # networks is a list of values under the person key
    # **networks_to_person[networks] = person**  # This should not be here
    for network in networks: # Now put the person under each network in networks list
      if network not in networks_to_person: #Now use each network as a key
        networks_to_person[network] = [person]
      else:
        networks_to_person[network].append(person) # Note that append needs ()

This means that every key value would have been the value [person, person] assuming you have fixed the first value to be [person] and not person.

sabbahillel
  • 4,357
  • 1
  • 19
  • 36
  • It still gives me an error says function s are not subscriptable. how can I fix this problem..? – user3477470 Mar 30 '14 at 23:48
  • @user3477470 I had to rush out to a meeting before I was able to put in the function problem explanation. I added it to the answer. – sabbahillel Mar 31 '14 at 00:08
  • Thanks for your comments. I did what you suggested, but I get an error on line networks= persom_to_networks[person]. It says function object is not subscriptable.. – user3477470 Mar 31 '14 at 00:22
  • @user3477470 Take a look at how I changed that line to networks = person_dict[person] using two methods of defining person_dict. That is the problem you are having. I think that I have expanded the explanation to show it. Please let me know if I have not explained what needs to be done adequately. – sabbahillel Mar 31 '14 at 00:32
  • Thanks for your help. Now I have an error in line if not(networks in networks_to_person): it says unhashable type: list. I have no clue for this error.. – user3477470 Mar 31 '14 at 00:40
  • @user3477470 try if networks not in networks_to_person: – sabbahillel Mar 31 '14 at 00:41
  • @user 3477470 I think that networks is probably actually a list so you need another for loop to get each network in networks. – sabbahillel Mar 31 '14 at 02:25
  • @user3477470 Since I do not have the code settings to actually run the dictionary, this is from code inspection. However, the way you describe it seems to show that networks is a list and you want to make each network in that list a separate key in which you now have a list of persons. – sabbahillel Mar 31 '14 at 02:34