How to print only the key values of a dictionary for a certain range based on the dictionary values?

Viewed 1060

Suppose I am having a Dictionary in the following format.

new_dict = {'worry': [23, 667, 1692, 1940], 'win': [96, 200, 286], 'work': [833, 1458]}

I want to print only the key only keys based on the values between 0 to 100.

Output in this case:

{'worry', 'win'}

I have tried:

dict0100 = {k:v for (k,v) in new_dict.items() if new_dict.values(range(100))}

I am getting error like values take only 1 argument.

Note: The values range between 0 to 5000 in my case. I want only the key values between 0 to 100 only.

Any help is appreciated.

5 Answers

Try this:

dict0100 = {k: v for (k, v) in new_dict.items() if any(i <= 100 for i in v)}

If you want the list to be filtered too:

dict0100 = {k: l for k, l in [(k, [i for i in v if i <= 100]) for k, v in new_dict.items()] if l}

Note about < or range

About using the comparison operator < or the in range() expression, I would personnaly go for the x < 100 since here all of the lists items are said to be positive integers, and comparison is more performant:

import timeit

t1 = timeit.timeit(lambda: 3 in range(100))
print(t1) # 0.37976

t2 = timeit.timeit(lambda: 3 <= 100)
print(t2) # 0.08725

I'd use a range check with any. Here's a neat reusable generator function:

def get_keys_in_range(dct, lo=0, hi=100):
    rng = range(lo, hi) 
    for key, lst in dct.items():
        if any(l in rng for l in lst):
            yield key

[*get_keys_in_range(new_dict, lo=0, hi=100)]
# ['worry', 'win']

It's worth mentioning that membership checks on range objects are constant time (O(1)) in python-3.x (but O(N) in python-2.x, so you may want to consider the other solutions using pure comparisons).

Note that the range is closed on the right interval, meaning you'd want to do range(lo, hi+1) if you want the upper bound to be inclusive.


This can be shortened to

lo, hi = 0, 100
[key for key, lst in new_dict.items() if any(l in range(lo, hi) for l in lst)]
# ['worry', 'win']

You can pre-cache range for a little more performance (as done inside the function).

rng = range(lo, hi)
[key for key, lst in new_dict.items() if any(l in rng for l in lst)]
# ['worry', 'win']

Try this:

dict0100 = {k:v for (k,v) in new_dict.items() if [x for x in v if all([x<100,x>0])]}

This will save both the key and the value, for key only remove the ":v"

your dict has keys of type str and values of type list (of ints)

your expected output is a set object (and not a dict).

try this:

new_dict = {'worry': [23, 667, 1692, 1940], 'win': [96, 200, 286], 'work': [833, 1458]}

set0100 = {k for k, arr in new_dict.items() if any(v in range(100) for v in arr)}

print(set0100)

this uses the nice fact that range objects implement the __contains__ method, which allows us to use in on them.

dict0100 = {k:v for (k,v) in new_dict.items() if all([v_e < 5000 for v_e in v])}

Related