tags:

views:

204

answers:

6

I have a dictionary with either a integer or a tuple of integers as value. How do I find the maximum integer present in dicts' values?

Example:

x1 = {0:2, 2:1, 3:(1, 2), 20:3}

should return 3 and

x2 = {0:2, 2:1, 3:(1, 5), 20:3}

should return 5

A: 

You could try this aproach:

  • create a set for storing integers
  • loop through the values of the dictionary
    • add integer values to set
    • add each integer value of tuple values to set
  • find max of set

Something like this:

def maxofdict(x):
   s = set()
   for v in x.values():
      if hasattr(v, '__len__'):
         s.update(v)
      else:
         s.add(v)
   return max(s)
Daren Thomas
A: 

You need a generic flatten() function. The Python standard library oddly enough doesn't provide one -- not even in itertools -- but googling around should get you an implementation. If you don't mind being potentially backwards incompatible, you can import a "private" implementation from tkinter:

from _tkinter import _flatten as flatten

def mixed_max(d):
    return max(flatten(d.items()))

mixed_max({0: 2, 2: 1, 3: (1,2), 4: 0}) # => 4
mixed_max({0: 2, 2: 1, 3: (1,5), 4: 0}) # => 5
llasram
-1 for recommending usage of implementation details. `_tkinter` is not a part of the public API, and can theoretically change at any time.
lunaryorn
@lunaryorn Um, yeah, I specifically say that. The implementation of the `flatten()` the poster wants is irrelevant, so grabbing one near at hand simplifies the example.
llasram
A: 

Assuming the correct result for x1 = 4;

def maxOfMixedDict(x):
    max = 0
    for key, value in x.items():
        if(key > max):
            max = key
        try:
            for v2 in value:
                if(v2 > max):
                    max = v2
        except TypeError, e:
            pass

    return max
babbitt
+3  A: 

A one-liner:

max(max(v) if isinstance(v, collections.Iterable) else v for v in d.itervalues())

Needs at least Python 2.6 due to collections.Iterable ABC.

lunaryorn
This doesn't seem to be what the OP wants.
NullUserException
@NUll: yeah, I'm sorry. I actually don't know what OP wants. But I think this the solution anyway :)
SilentGhost
+1 for one-liner.
Theodor
@Theodor I am confused. This ignores the dict's keys completely; are you sure this is what you want?
NullUserException
@Theodor: this gives 2 for your first example; you specified 3.
katrielalex
@Theodor: Either this answer is incorrect or your examples are incorrect. This gives 2 as the max for `x1`, not 3.
Will McCutchen
Im sorry. I changed the examples above. My bad. Now, this solution returns the correct values. Again, Sorry.
Theodor
I guess, the expected solution presented for the first example is a typo. 3 doesn't make sense at all, because the maximum with keys included would be 4. In either case, I've updated my answer with an example which includes the keys.
lunaryorn
@lunaryorn: it open another can of worms. OP updated his question, it was indeed a typo and your answer is correct. No need to spoil it with some fantasies.
SilentGhost
Oh, now I see your point. No, I dont wish to search the keys, thanks for including that though.
Theodor
@SilentGhost: Keep cool ... I simply didn't notice his update while I was still updating mine. Thanks for reverting my answer to the correct one, but there is no need to polish your ego with that.
lunaryorn
+1  A: 
max(max(k,max(v) if isinstance(v,collections.Iterable) else v) for k,v in x1.items())

The other one-liner does not take account of the keys.

This is icky because it is not the designed use of a dictionary: the keys are meant to be keys, not themselves stores of data. I think you should reconsider your data structure.

EDIT: The above was nonsense. Thanks to @SilentGhost for pointing it out.

katrielalex
this returns 4 for `x1`
SilentGhost
@SilentGhost: so it does. Silly OP.
katrielalex
you don't need to do `max(x1.keys())`, you could just do `max(x1)`. but beyond you code just doesn't make sense.
SilentGhost
@Silent I think that was for clarification purposes. +1 to the answer for mentioning this is not how dicts are meant to be used
NullUserException
@Null: what it has to with clarification? those 3 lines make no sense, would raise `TypeError` on the second line even if correct syntax was used for `max_values`!
SilentGhost
@SilentGhost: I missed a `max`; hopefully they now make sense. The `keys()` was indeed for clarification.
katrielalex
@katrie: no, you didn't miss `max`. doing `tuple(3)` raises `TypeError` in Python, because `3` is not an iterable! And again, you're not iterating over values with `for v in x1`, you're iterating over keys!
SilentGhost
@SilentGhost: you are all too right. Thanks.
katrielalex
+1  A: 

This is my version of one liner not needing 2.6:

x1 = {0:2, 2:1, 3:(1, 2), 20:3}
x2 = {0:2, 2:1, 3:(1, 5), 20:3}
print max(max(values) if hasattr(values,'__iter__') else values for values in x1.values()) 
print max(max(values) if hasattr(values,'__iter__') else values for values in x2.values()) 

Output:

3
5

HOWEVER I strongly suggest to go to origin of these values and change the storing of integers to singleton tuples.Then you can use cleaner code:

x1 = {0:(2,), 2:(1,), 3:(1, 2), 20:(3,)}
x2 = {0:(2,), 2:(1,), 3:(1, 5), 20:(3,)}
for x in (x1,x2):
    print max(max(values) for values in x.values())
Tony Veijalainen
Good idea. Hey your allmost at 1000 rep. Congratulations =)
Theodor
And it fits that I have just founded company called Ysisoft (Ninesoft) 9.9.2010 9 o'clock and rep is in 990's :)
Tony Veijalainen