1

How to compare only the values of two dictonaries?

So I have this:

dict1 = {"appe": 3962.00, "waspeen": 3304.08}
dic2 = {"appel": 3962.00, "waspeen": 3304.08}


def compare_value_dict(dic):
    return dic

def compare_value_dict2(dic2):   
    return dic2
    

def compare_dic(dic1, dic2):
    if dic1 == dic2:       
        print('the same dictionary')
    else:      
        print('difference dictionary')

compare_dic(compare_value_dict(dict1).values(), compare_value_dict2(dic2.values()))

this works:

compare_dic(compare_value_dict(dict1).keys(), compare_value_dict2(dic2.keys()))
mightycode Newton
  • 3,229
  • 3
  • 28
  • 54
  • Why include and use the `compare_value_dict()` and `compare_value_dict2()` functions in this question? They don't do anything but return their single argument. – Martijn Pieters Nov 27 '22 at 16:02
  • @MartijnPieters. Because this is for testing. I have two larger functions thar returns the key an value. But only the value has to be compared with the other returned value – mightycode Newton Nov 27 '22 at 16:04
  • Does this answer your question? [Comparing two dictionaries and checking how many (key, value) pairs are equal](https://stackoverflow.com/questions/4527942/comparing-two-dictionaries-and-checking-how-many-key-value-pairs-are-equal) – tevemadar Nov 27 '22 at 16:04
  • @tevemadar. I only want to compare the value not both. Not the key, only the value. – mightycode Newton Nov 27 '22 at 16:05
  • 1
    Which are the comparison criteria? I do get why you think those dictionaries are equal. Because the "similar looking" fields have the same values. But what are "similar looking" fields? You need to choose that. For example, is `{"appel":3304.08, "waspeen":3962}` also have the same values? – chrslg Nov 27 '22 at 16:05
  • @chrslg: their *values* are equal. – Martijn Pieters Nov 27 '22 at 16:08
  • If keys do not matter, you could build lists of the values, order them, and then compare. – tevemadar Nov 27 '22 at 16:09
  • If not, how to you tell the difference. Not from the field name, if I understand correctly the comment you typed while I was asking my question. But from what, then? Dictionaries are not ordered. – chrslg Nov 27 '22 at 16:09
  • you can go with the function dic.keys() that returns a vector containing all "headers" from your dictionary. And in the for loop, you can compare. – David Rura Nov 27 '22 at 16:08

3 Answers3

6

You can't use == on the dict.values() dictionary view objects, as that specific type doesn't act like a set. Instead values_view_foo == values_view_bar is only ever true if both refer to the same dictionary view object. The contents don't matter.

It'll depend entirely on the types of values that the dictionary contains on what techniques can be used here. The following options will cover many different types of values, but not all. It is not really possible to make a generic one-size-fits-all comparison function for all possible types of values in a dictionary.

In this specific case, you can turn your values views into sets, because the values happen to both be unique and hashable:

def compare_dict_values(dv1, dv2):
    """Compare two dictionary values views

    Values are assumed to be unique and hashable

    """
    return set(dv1) == set(dv2)

Where the values are not unique, and / or not hashable, you'll have to find another way to compare the values.

If they are, say, sortable (orderable), then you could compare them by first sorting the values:

def compare_dict_values(dv1, dv2):
    """Compare two dictionary value views

    Values are assumed to be orderable, but do not need to be unique
    or hashable.

    """
    return len(dv1) == len(dv2) and sorted(dv1) == sorted(dv2)

By sorting you remove the issue with the values view being unordered. The len() check is there because it is much cheaper than sorting and so let’s you avoid the sort when it is not necessary.

If the values are hashable but not unique (and so the values collection ('foo', 'bar', 'foo') is different from ('foo', 'bar', 'bar')), you can use Counter() objects to capture both the values and their counts:

from collections import Counter

def compare_dict_values(dv1, dv2):
    """Compare two dictionary value views

    Values are assumed to be hashable, but do not need to be unique.

    """
    return Counter(dv1) == Counter(dv2)

Note: Each of these techniques assume that the individual values in the dictionary support equality testing and you only need them to be exactly equal. For floating point values, you can run into issues where the values are almost equal, but not exactly equal. If your values need to be close and not just exactly equal, you can use the math.isclose() function on each pair of values. Use zip(sorted(dv1), sorted(dv2)) to pair up the values:

def float_dict_values_close(dv1, dv2, **kwargs):
    """Compare two dictionary view objects with floats

    Returns true if the values in both dictionary views are
    *close* in value.

    """
    if len(dv1) != len(dv2):
        return False
    v1, v2 = sorted(dv1), sorted(dv2)
    return all(is_close(*vs, **kwargs) for vs in zip(v1, v2))

Things get more complicated if your values can be different types; you generally can't sort a dictionary values view with a mix of different types in it. If you have a mix of types where not all the types are hashable, you'd have to separate out the different types first and then use a mixture of techniques to compare the values of the same type. This gets complicated when you have a hierarchy of types where subclasses can be compared with superclasses, etc. I'm declaring that as outside the scope of this answer.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    It is not guaranteed to work tho. Because `0.1+0.2==0.3` is False. Never ever compare float values with `==` – chrslg Nov 27 '22 at 16:16
  • @chrslg: sure, it depends on how comparable the exact values are, too. That's separate issue from being able to hash the values and if they are unique. – Martijn Pieters Nov 27 '22 at 16:18
  • @chrslg: I added a section on that, since the OP is using floating point numbers as values. It is not clear that close equivalence is a requirement, however. – Martijn Pieters Nov 27 '22 at 16:23
  • Not really a separate issue. Because (unless I ignore a trick to pass sets a comparison function) you can't use the `set(d1.values())==set(d2.values())` method if the comparison function `==` is not valid for elements of those sets. Note that there are no exact values in floats. It is not about adding a tolerance. See my previous example. Since parsing is deterministic, you can probably count on the fact that `0.1==0.1`. But I take if one need comparison it is because origin of the values are not the same. – chrslg Nov 27 '22 at 16:24
  • And it is not just about numerical error accumulation. There are float values that are ambiguous. `0.999999999999999944488848768742172978818416595458984375` for example, is exactly at the mid point of two floating points value (one that would print as 1, another that would print as ` 0.9999999999999999`. So, no guarantee about how it is represented. – chrslg Nov 27 '22 at 16:28
  • 2
    @chrslg: I am aware of how floats work. That you can use syntax to create a float value that's not actually exactly equal to the actual value is very far outside the scope of this question. The spirit of the question is to compare dictionary values, and I have quite clearly documented the constraints under which you can do so. I am giving the **general answer** here to make it useful for the widest possible audience. Muddling this with the peculiarities of float values is not helping, to be honest. – Martijn Pieters Nov 27 '22 at 16:33
  • 1
    Wow. I did not intend to get in a fight, especially not with you. Even without the near 1M reputation, I have encountered enough of your answer to know that you are generally right. But the argument is muddling only because we are having it. See my answer (I think you already have): I don't think it is muddling. I am just stating a very well known fact (don't compare float with `==`) to justify using comparison on sorted values instead. (Btw, really not a rebuttal, I was about to mention it when your comment arrived. But I don't think you can use `as` as a variable name) – chrslg Nov 27 '22 at 16:38
  • @chrslg: sorry, I didn't realise you found me combative in my arguments. Thanks for pointing out the `as` error, it's indeed a reserved keyword. – Martijn Pieters Nov 27 '22 at 16:41
1

so you wanna check if your dictionaries are same with their values right?

dict1 = {"appe": 3962.00, "waspeen": 3304.08}
dic2 = {"appel": 3304.08, "waspeen": 3962.00}
def comparision(*dicts):
    instanceToCompare , values = len(dicts[0].values()) , set()
    for d in dicts:
        for value in d.values():
            values.add(value)
    return True if len(values) == instanceToCompare else False
print('all dictionaries has same values') if comparision(dict1 , dic2) else 
print('input dictionaries are not same at all')

you'll know if all values in dictionaries are same or not , regardless to their order or repitation

  • This assumes that the values are hashable and unique. Don’t use `True if [test] else False`, **the test itself is already producing a boolean**. Just use `return len(values) == instanceToCompare`. – Martijn Pieters Nov 27 '22 at 18:06
  • This fails the moment that there are non-unique values in either dictionary, especially if they are of different lengths. E.g. one dict has `42.0, 42.0` and the other has `17.0`, your test returns True. – Martijn Pieters Nov 27 '22 at 18:08
  • Instead of looping and using `set.add()` you can create a union of all the values of all the dictionaries with: `values = set().union(*(d.values() for d in dicts))`. Not that that will resolve the inherent problems with the answer of course. – Martijn Pieters Nov 27 '22 at 18:12
-1

you can go with the function dic.keys() that returns a vector containing all "headers" from your dictionary. And in the for loop, you can compare.

David Rura
  • 21
  • 2
  • 1
    This is not what the question is asking for however. The two dictionaries in question have different keys. The keys don't actually matter, you can loop over the values view just fine (`for value in somedict.values()` works), the problem then is _in what order_ do you compare them. Using the keys of the dictionaries will not solve that problem. – Martijn Pieters Nov 27 '22 at 16:11