过度计算python循环中的对

时间:2017-06-21 09:43:59

标签: python list dictionary counting

我有一个词典列表,每个词典的格式如下:

 {'A': a,'B': b}

我想遍历列表,并且对于每个(a,b)对,找到对(b,a),如果它存在。

例如,如果对于列表A = 13和B = 14的给定条目,则原始对将是(13,14)。我想搜索整个dicts列表以找到该对(14,13)。如果(14,13)多次发生,我也想记录。

我想计算列表中所有原始(a,b)对的次数,当补码(b,a)出现时,如果是,则计算多少次。要做到这一点,我找到了两个for循环和一个计数器。

pairs_found = 0
for i, val in enumerate( list_of_dicts ):
    for j, vol in enumerate( list_of_dicts ):
        if val['A'] == vol['B']:
            if vol['A'] == val['B']:
                pairs_found += 1

这会产生大于pairs_found长度的list_of_dicts。我意识到这是因为相同的对将被过度计算。我不确定如何克服这种堕落?

编辑清晰度

list_of_dicts = []

list_of_dicts[0] = {'A': 14, 'B', 23}
list_of_dicts[1] = {'A': 235, 'B', 98}
list_of_dicts[2] = {'A': 686, 'B', 999}
list_of_dicts[3] = {'A': 128, 'B', 123}

....

让我们说该列表有大约100000个条目。在该列表的某处,将有一个或多个条目,形式为{'A'23,'B':14}。如果这是真的那么我想要一个计数器将其值增加一。我想为列表中的每个值执行此操作。

4 个答案:

答案 0 :(得分:2)

以下是我的建议:

  • 使用元组表示您的对并将它们用作dict / set键。
  • 构建一组您将寻找的独特倒置对。
  • 使用dict存储一对倒置的时间

然后代码应如下所示:

# Create a set of unique inverted pairs    
inverted_pairs_set = {(d['B'],d['A']) for d in list_of_dicts}
# Create a counter for original pairs
pairs_counter_dict = {(ip[1],ip[0]):0 for ip in inverted_pairs_set]
# Create list of pairs
pairs_list = [(d['A'],d['B']) for d in list_of_dicts]
# Count for each inverted pairs, how many times 
for p in pairs_list:
   if p in inverted_pairs_set:
      pairs_counter_dict[(p[1],p[0])] += 1

答案 1 :(得分:1)

您可以先创建一个列表,其中每个字典的值为元组:

example_dict = [{"A": 1, "B": 2}, {"A": 4, "B": 3}, {"A": 5, "B": 1}, {"A": 2, "B": 1}]
dict_values = [tuple(x.values()) for x in example_dict]

然后创建第二个列表,其中每个元素的出现次数都被反转:

occurrences = [dict_values.count(x[::-1]) for x in dict_values]

最后,创建一个以dict_values为键,occurrences为值的词典:

dict(zip(dict_values, occurrences))

输出:

{(1, 2): 1, (2, 1): 1, (4, 3): 0, (5, 1): 0}

对于每个键,您都有反转键的数量。您还可以动态创建字典:

occurrences = {dict_values: dict_values.count(x[::-1]) for x in dict_values}

答案 2 :(得分:1)

我仍然不能100%确定你想做什么,但这是我的

pairs_found = 0
for i, dict1 in enumerate(list_of_dicts):
    for j, dict2 in enumerate(list_of_dicts[i+1:]):
        if dict1['A'] == dict2['B'] and dict1['B'] == dict2['A']:
            pairs_found += 1

请注意第二个for循环上的切片。这避免了检查之前已经检查过的对(将D1与D2进行比较就足够了;不需要将D2与D1进行比较)

这比O(n ** 2)好,但仍有改进的余地

答案 3 :(得分:1)

您可以创建一个包含所有词典中'A''B'键值的计数器词典:

complements_cnt = {(dct['A'], dct['B']): 0 for dct in list_of_dicts}

然后您需要的是再次遍历您的词典并增加"补充"的值:

for dct in list_of_dicts:
    try:
        complements_cnt[(dct['B'], dct['A'])] += 1
    except KeyError:   # in case there is no complement there is nothing to increase
        pass

例如,使用list_of_dicts

list_of_dicts = [{'A': 1, 'B': 2}, {'A': 2, 'B': 1}, {'A': 1, 'B': 2}]

这给出了:

{(1, 2): 1, (2, 1): 2}   

基本上说{'A': 1, 'B': 2}有一个补码(第二个)而{'A': 2, 'B': 1}有两个(第一个和最后一个)。

解决方案是O(n),即使对于100000个词典也应该非常快。

注意:这与@debzsud答案非常相似。在我发布答案之前,我还没有看到它。 :(