Better way to do this dict comprehesion

Peter Otten __peter__ at web.de
Wed Mar 8 03:20:24 EST 2017


Sayth Renshaw wrote:

> Hi
> 
> I have got this dictionary comprehension and it works but how can I do it
> better?

List comprehensions (that's what you have) are nice, but overused.

 
> from collections import Counter
> 
> def find_it(seq):
>      counts = dict(Counter(seq))

There is no need to convert Counter to dict.

>      a = [(k, v) for k,v in counts.items() if v % 3 == 0]
>      return a[0][0]
> 
> test_seq = [20,1,-1,2,-2,3,3,5,5,1,2,4,20,4,-1,-2,5]
> 
> so this returns 5 which is great and the point of the problem I was doing.
> 
> Can also do it like this
> def find_it(seq):
>      counts = dict(Counter(seq))
>      a = [(k) for k,v in counts.items() if v % 3 == 0]
>      return a[0]
> 
> But the given problem states there will always only be one number
> appearing an odd number of times given that is there a neater way to get
> the answer?

If you mean there is only one number satisfying the v % 3 == 0 condition 
then there is no need to go through the whole sequence. The clearest way to 
express that is

    for k, v in counts.items():
        if v % 3 == 0:
            return k
    raise ValueError

but

    it = (k for k, v in counts.items() if v % 3 == 0)
    try:
        return next(it)
    except StopIteration:
        pass
    raise ValueError

is also possible. The parens (...) instead of [...] make "it" generator 
expression which is evaluated lazily. 

Both alternatives shown above ensure that at least one value satisfies the 
condition "number of occurencies divides by three without rest". If you want 
to play it safe and verify that there is exactly one such key you may keep 
the listcomp, preferably that from your second implementation.

    a = [...]
    if len(a) != 1:
        raise ValueError
    return a[0]

or

    [result] = a  # will raise a ValueError if len(a) != 1

The complete code:

>>> from collections import Counter
>>> def find_it(seq):
...     [result] = [k for k, v in Counter(seq).items() if v % 3 == 0]
...     return result
... 
>>> test_seq = [20,1,-1,2,-2,3,3,5,5,1,2,4,20,4,-1,-2,5]
>>> find_it(test_seq)
5





More information about the Python-list mailing list