n00bprogrammer22 n00bprogrammer22 - 24 days ago 7
Python Question

Searching for keys in dictionary that have a value between two numbers

I need to analyze a dictionary for values that include a number between two given numbers (as parameters) and return those values preceded by their key

Dictionary:

{'P':[("Eight",1460, 225.0, 200.0, "fresco","Netherlands"),("Six",1465,81.0, 127.1, "tempera", "Netherlands")],
'V':[("Four",1661, 148.0, 257.0,"oil paint", "Austria"),("Two",1630, 91.0, 77.0, "oil paint","USA")],
'K':[("Five",1922,63.8,48.1,"watercolor","USA"),("Seven",1950,61.0,61.0,"acrylic paint","USA"),("Two",1965,81.3,100.3,"oil paint","United Kingdom")],
'C':[("Ten",1496,365.0,389.0,"tempera","Italy")],
'U':[("Nine",1203,182.0, 957.0,"egg tempera","Italy"), ("Twelve",1200,76.2,101.6,"egg tempera","France")]
}


The function should only return the values where a number between the two numbers is present. So if the function was called between_two_values it should return this if searching for values between 1464 and 1496:

between_two_values(dictionary1(), 1464, 1496)

{'P': [('Six', 1465, 81.0, 127.1, 'tempera',
'Netherlands')], 'C': [('Ten', 1496, 365.0,
389.0, 'tempera', 'Italy')]}


If one of the values of the key doesn't have a number between 1464-1496 it shouldnt return that value and only the ones that have a number in that range preceded by its key. This is why in the above example for 'P' the first value which has 1460 wasnt returned since it is not between the 2 numbers. The first number in the function should always be smaller then the second if the first number is larger then it should just return an empty dictionary.

This is the code I have come up with I don't think it's correct but it kind of shows the logic that could solve this function. I appreciate any help I receive

def between_two_values(dictionary,start,end):
for x in dictionary:
if end < x < start in dictionary:
return dictionary(x)

Answer

You're on the right track. Here's one solution to the problem posed.

I've formatted the data better for clarity. When it was condensed down I didn't immediately see that each dictionary value was wrapped in a list. Of course this is a style-oriented change, but style helps with readability.

Note that I have made a few assumptions, such as that each dictionary value will be a list. For example, that your edge case of a key with no values will be represented as [] rather than None. I have also sort of extrapolated what I think the desired output is from the example you gave. Finally, you may consider using collections.defaultdict to simplify where matches are stored.

Besides that, this code is nothing fancy. You certainly could condense it down more, or use classes for semantics. Speaking of semantics, I recommend that you use better variable names than I did: "data", "record", and "value" are pretty generic, but I feel they helped explain the solution without me having insight as to what this data represents.

Data

data = {
    'P': [
        ('Eight', 1460, 225.0, 200.0, 'fresco', 'Netherlands'), 
        ('Six', 1465, 81.0, 127.1, 'tempera', 'Netherlands'), 
    ], 
    'V': [
        ('Four', 1661, 148.0, 257.0, 'oil paint', 'Austria'), 
        ('Two', 1630, 91.0, 77.0, 'oil paint', 'USA'), 
    ], 
    'K': [
        ('Five', 1922, 63.8, 48.1, 'watercolor', 'USA'), 
        ('Seven', 1950, 61.0, 61.0, 'acrylic paint', 'USA'), 
        ('Two', 1965, 81.3, 100.3, 'oil paint', 'United Kingdom'), 
    ], 
    'C': [
        ('Ten', 1496, 365.0, 389.0, 'tempera', 'Italy'), 
    ], 
    'U': [
        ('Nine', 1203, 182.0, 957.0, 'egg tempera', 'Italy'), 
        ('Twelve', 1200, 76.2, 101.6, 'egg tempera', 'France'), 
    ], 
}

Code

def between_two_values(dictionary, start, end):
    matches = {}
    for key, record_list in dictionary.items():
        for record in record_list:
            value = record[1]
            if start < value < end:
                if key in matches:
                    matches[key].append(record)
                else:
                    matches[key] = [record]
    return matches

result = between_two_values(data, 1464, 1496)
print(result)

Output

{'P': [('Six', 1465, 81.0, 127.1, 'tempera', 'Netherlands')]}