Python3:测试字典的所有值是否相等 - 当值未知时

时间:2017-07-10 20:06:59

标签: python python-3.x dictionary

我有2个词典: 每个字典中的值都应该相等 但是我不知道这个数字会是什么......

dict1 = {'xx':A, 'yy':A, 'zz':A}
dict2 = {'xx':B, 'yy':B, 'zz':B}

N.B。 A不等于B
N.B。 A和B实际上都是十进制数字的字符串(例如'-2.304998'),因为它们是从文本文件中提取的

我想创建另一个字典 - 有效地总结这些数据 - 但前提是每个字典中的所有值都相同。

summary = {}
if dict1['xx'] == dict1['yy'] == dict1['zz']:
    summary['s'] = dict1['xx']
if dict2['xx'] == dict2['yy'] == dict2['zz']:
    summary['hf'] = dict2['xx']

有一种巧妙的方法可以在一行中完成这项工作吗?

我知道可以使用理解来创建字典 summary = {k:v for (k,v) in zip(iterable1, iterable2)}
但我正在努力与底层的for循环和if语句......

一些建议将不胜感激。

我见过this question,但答案似乎都依赖于已经知道正在测试的值(即字典中的所有条目都等于已知数字) - 除非我遗漏了一些东西。

5 个答案:

答案 0 :(得分:7)

set是一种可靠的方式,但仅仅为了代码高尔夫目的,这里有一个可以处理不可清除的dict值的版本:

expected_value = next(iter(dict1.values())) # check for an empty dictionary first if that's possible
all_equal = all(value == expected_value for value in dict1.values())

all在不匹配的情况下提前终止,但是设置的构造函数已经足够优化,以至于在没有对真实测试数据进行分析的情况下,我不会说这很重要。处理不可排除的值是此版本的主要优势。

答案 1 :(得分:5)

虽然我们可以使用set,但是当输入很大时,这样做会产生很多效率低下的问题。它可以占用与输入大小成比例的内存,并且它总是扫描整个输入,即使早期发现两个不同的值。此外,输入必须是可清除的。

对于3键词,这没关系,但对于较大的词,我们可以使用itertools.groupby而不是set,看看它是否会产生多个组:

import itertools

groups = itertools.groupby(dict1.values())

# Consume one group if there is one, then see if there's another.
next(groups, None)
if next(groups, None) is None:
    # All values are equal.
    do_something()
else:
    # Unequal values detected.
    do_something_else()

答案 2 :(得分:4)

这样做的一种方法是利用set。您知道如果只有一个值,则set的iterable的长度为1:

if len(set(dct.values())) == 1:
    summary[k] = next(iter(dct.values()))

当然,这只适用于您的字典值可以播放的情况。

答案 3 :(得分:1)

除了可读性之外,我不关心涉及set或.values的所有答案。所有这些总是 O(N)的时间和内存。在实践中它可以更快,但它取决于值的分布。

另外因为set采用散列操作,你的时间成本也可能有一个很大的常数乘数。当你需要测试平等时,你的价值观必须是可以清洗的。

理论上理论上更好地从字典中获取第一个值并在其余值中搜索不等于的第一个示例。 set 可能比下面的解决方案更快,因为它的工作原理可能会减少到C实现。

def all_values_equal(d):
    if len(d)<=1: return True # Treat len0 len1 as all equal
    i = d.itervalues()
    firstval = i.next()
    try:
        # Incrementally generate all values not equal to firstval
        # .next raises StopIteration if empty.
        (j for j in i if j!=firstval).next()
        return False
    except StopIteration:
        return True

print all_values_equal({1:0, 2:1, 3:0, 4:0, 5:0}) # False
print all_values_equal({1:0, 2:0, 3:0, 4:0, 5:0}) # True
print all_values_equal({1:"A", 2:"B", 3:"A", 4:"A", 5:"A"}) # False
print all_values_equal({1:"A", 2:"A", 3:"A", 4:"A", 5:"A"}) # True

在上面:

(j for j in i if j!=firstval)

相当于:

def gen_neq(i, val):
    """
    Give me the values of iterator i that are not equal to val
    """
    for j in i:
        if j!=val:
            yield j

答案 4 :(得分:0)

我找到了这个解决方案,我发现我结合了这里找到的另一个解决方案:enter link description here

user_min = {'test':1,'test2':2}
all(value == list(user_min.values())[0] for value in user_min.values())

>>> user_min = {'test':1,'test2':2}
>>> all(value == list(user_min.values())[0] for value in user_min.values())
False
>>> user_min = {'test':2,'test2':2}
>>> all(value == list(user_min.values())[0] for value in user_min.values())
True
>>> user_min = {'test':'A','test2':'B'}
>>> all(value == list(user_min.values())[0] for value in user_min.values())
False
>>> user_min = {'test':'A','test2':'A'}
>>> all(value == list(user_min.values())[0] for value in user_min.values())
True

适用于小型词典,但是我不确定大型词典,因为我们可以通过所有值选择第一个词典