-4

I am trying to sort a dictionary by list of lists. The items in the list of lists are keys in the dictionary. I asked it before but the answers didn't solve the issue.

My input list is:

   mylist= [
    ['why', 'was', 'cinderella', 'late', 'for', 'the', 'ball', 'she', 'forgot', 'to', 'swing', 'the', 'bat'],
    ['why', 'is', 'the', 'little', 'duck', 'always', 'so', 'sad', 'because', 'he', 'always', 'sees', 'a', 'bill', 'in', 'front', 'of', 'his', 'face'],
    ['what', 'has', 'four', 'legs', 'and', 'goes', 'booo', 'a', 'cow', 'with', 'a', 'cold'], 
    ['what', 'is', 'a', 'caterpillar', 'afraid', 'of', 'a', 'dogerpillar'],
    ['what', 'did', 'the', 'crop', 'say', 'to', 'the', 'farmer', 'why', 'are', 'you', 'always', 'picking', 'on', 'me']
    ]

My dictionary somewhat looks like this:

    myDict = {'to': [7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56], 
    'jam': [20], 'black': [5], 'farmer': [11],
    'woodchuck': [54], 'has': [14, 16, 51], 'who': [16]
    }

My code is:

    def sort_by_increasing_order(mylist, myDict):
    #temp = sorted(myDict, key=myDict.get)
    temp = sorted(myDict, key=lambda tempKey: for tempKey in mylist, reverse=True )
    return temp

Something like:

    sort_by_increasing_order(['d', 'e', 'f'], {'d': [0, 1], 'e': [1, 2, 3], 'f': [4]})
    result: ['f', 'e', 'd']

So for my sample input it would look like:

        sort_by_increasing_order(mylist, myDict)
        >> ['to','woodchuck','has','jam','who','farmer']

The commented line just sorts by the dictionary keys when i try to sort by the list. My approach is not correct. The result should a list with increasing order of the length of indices as mentioned above. Any suggestion.

user3247054
  • 431
  • 1
  • 5
  • 9

3 Answers3

2

With reference to @doukremt answer assuming you are aware of decorators.

mydict = {'d': [0, 1], 'e': [1, 2, 3], 'f': [4]}
mylist = [['d', 'e', 'f', 'c'], ['c', 'v', 'd', 'n']]

def convert_to_set(mylist, result_set=None):
    if result_set is None:
        result_set = []
    for item in mylist:
        if isinstance(item, str):
            result_set.append(item)
        if isinstance(item, list):
            convert_to_set(item, result_set)
    return set(result_set)

def list_to_set(f):
    def wrapper(mylist, mydict):
        myset = convert_to_set(mylist)
        result = f(myset, mydict)
        return result
    return wrapper

@list_to_set
def findit(mylist, mydict):
    gen = ((k, mydict[k]) for k in mylist if k in mydict)
    return [k for k, v in sorted(gen, key=lambda p: len(p[1]))]

print findit(mylist, mydict)
Nikhil Rupanawar
  • 4,061
  • 10
  • 35
  • 51
  • Thanks a lot for your answer. Let me try it out. I am sorry i am not aware of decorators. If you could explain what your code is doing that would be great. – user3247054 Jan 30 '14 at 08:50
  • 1
    http://stackoverflow.com/questions/739654/how-can-i-make-a-chain-of-function-decorators-in-python/1594484#1594484 here – Nikhil Rupanawar Jan 30 '14 at 08:52
  • Thanks. Let me try it out. – user3247054 Jan 30 '14 at 08:55
  • can you please explain the flow etc, it would be helpful. I am not able to understand it. Thanks – user3247054 Jan 30 '14 at 09:47
  • Ok. I have converted nested list to set. so that all keywords in list and sublist will be inside set (without duplicate). Decorator is to just convert your nested list parameter (mylist) to set. Now, findit will operate on set instaed of original mylist. in short [['d', 'e', 'f', 'c'], ['c', 'v', 'd', 'n']] => {'d', 'e', 'c', 'v', 'f', 'n'} – Nikhil Rupanawar Jan 30 '14 at 10:31
  • :) Hope this will solve your problem – Nikhil Rupanawar Jan 30 '14 at 10:35
1
>>> D= {'to': [7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56], 
...     'jam': [20], 'black': [5], 'farmer': [11],
...     'woodchuck': [54], 'has': [14, 16, 51], 'who': [16]
...     }
>>> 
>>> sorted(D, key=lambda k:len(D[k]), reverse=True)
['to', 'has', 'who', 'jam', 'black', 'farmer', 'woodchuck']

For the values

>>> sorted(D.values(), key=len, reverse=True)
[[7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56], [14, 16, 51], [16], [20], [5], [11], [54]]

For (keys, values)

>>> sorted(D.items(), key=lambda i:len(i[1]), reverse=True)
[('to', [7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56]), ('has', [14, 16, 51]), ('who', [16]), ('jam', [20]), ('black', [5]), ('farmer', [11]), ('woodchuck', [54])]

Edit: Still not really clear what you are asking for. Your example doesn't seem to care about the length at all, otherwise "has" should come before "woodchuck"? Changing len to max may be what you want

>>> D = {'to': [7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56], 
...     'jam': [20], 'black': [5], 'farmer': [11],
...     'woodchuck': [54], 'has': [14, 16, 51], 'who': [16]
...     }
>>> 
>>> sorted(D, key=lambda k:max(D[k]), reverse=True)
['to', 'woodchuck', 'has', 'jam', 'who', 'farmer', 'black']
>>> sorted(D.values(), key=max, reverse=True)
[[7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56], [54], [14, 16, 51], [20], [16], [11], [5]]
>>> sorted(D.items(), key=lambda i:max(i[1]), reverse=True)
[('to', [7, 11, 17, 23, 24, 25, 26, 33, 34, 37, 39, 41, 47, 48, 53, 56]), ('woodchuck', [54]), ('has', [14, 16, 51]), ('jam', [20]), ('who', [16]), ('farmer', [11]), ('black', [5])]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
1
def findit(mylist, mydict):
    gen = ((k, mydict[k]) for k in mylist if k in mydict)
    return [k for k, v in sorted(gen, key=lambda p: len(p[1]))]


>>> findit(['d', 'e', 'f'], {'d': [0, 1], 'e': [1, 2, 3], 'f': [4]})
['f', 'd', 'e']
michaelmeyer
  • 7,985
  • 7
  • 30
  • 36
  • Thanks for your answer. But i get TypeError: unhashable type: 'list'. If yours is doing on single list, while i have list of lists posted above. – user3247054 Jan 30 '14 at 06:14
  • @user3247054: Then you must either convert your nested lists to tuples, or use a different data structure. You can't search for lists in dictionaries – michaelmeyer Jan 30 '14 at 06:21
  • If I understood correctly, You have list of list keywords, keyword can be present in any sub list. So, I would suggest convert list of list to single set so that it will contains all keywords as strings and use above code. List are not hashable so can not be used as dict keys. – Nikhil Rupanawar Jan 30 '14 at 07:13
  • @doukremt if want to return the indices. what would be change in the code? – user3247054 Jan 30 '14 at 08:21
  • Never mind figured it out. – user3247054 Jan 30 '14 at 08:26