Сравните два значения dict, сохраняя минимальное значение - PullRequest
1 голос
/ 25 апреля 2020

Я пытаюсь написать функцию, которая принимает два диктата и возвращает объединенный диктат, содержащий все ключи от обоих диктов, и, если какие-либо ключи существуют в обоих диктантах, сравнивает prices для сохранения наименьшего значения.

x = "{'45': 450, '43': 500, '44.5': 420, '39': 415, '47': 320, '46': 520, '44': 400, '47.5': 480, '40.5': 407, '42.5': 407, '42': 401, '38': 401, '45.5': 435, '37.5': 415, '41': 506, '38.5': 787, '36': 399, '36.5': 410, '48.5': 380, '40': 406, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}"
y = "{'36': 345.0, '36.5': 360.0, '37.5': 355.0, '38': 375.0, '38.5': 375.0, '39': 370.0, '40': 380.0, '40.5': 395.0, '41': 345.0, '42': 300.0, '42.5': 230.0, '43': 220.0, '44': 220.0, '44.5': 220.0, '45': 220.0, '45.5': 290.0, '46': 225.0, '47': 300.0, '47.5': 265.0, '48': 425.0, '48.5': 275.0, '49': 2000.0, '49.5': 1350.0, '51.5': 2000.0}"

Я написал эту функцию, чтобы сделать это, но я верю, что она может быть написана более pythoni c способом

import ast
def compare_prices(dict1,dict2):
    temp1 = ast.literal_eval(dict1)
    temp2 = ast.literal_eval(dict2)
    for k,v in temp1.items():
        if k in temp2.keys():
            price = temp2[k] if temp2[k] else False
            if price:
                if v> price:
                    temp1[k] = price
                else:
                    temp1[k] = v
            else:
                temp1[k] = v
        else:
            temp1[k] = v
    for k,v in temp2.items():
        if k not in temp1.keys():
            try:
                temp1[k] = v if v else ''
            except TypeError:
                temp1[k] = v
    return dict(sorted(temp1.items()))

Ответы [ 3 ]

2 голосов
/ 25 апреля 2020

Я считаю, что это будет соответствовать вашим требованиям. Это намного проще, поскольку он использует наборы ключей, так что set1.intersection(set2) содержит все ключи в обоих наборах, поэтому он может использовать это для сравнения, а set2-set1 просто содержит те, которые уникальны для set2, поэтому они могут просто переместиться на set1

def compare_prices(dict1,dict2):
    temp1 = ast.literal_eval(dict1)
    temp2 = ast.literal_eval(dict2)
    set1 = set(temp1.keys())
    set2 = set(temp2.keys())
    for k in set1.intersection(set2):
        if temp1[k] > temp2[k]:
            temp1[k] = temp2[k]
    for k in set2 - set1:
        temp1[k] = temp2[k]
    return dict(sorted(temp1.items()))

Вывод:

print(compare_prices(x, y))
{'36': 345.0, '36.5': 360.0, '37.5': 355.0, '38': 375.0, '38.5': 375.0, '39': 370.0, '40': 380.0, '40.5': 395.0, '41': 345.0, '42': 300.0, '42.5': 230.0, '43': 220.0, '44': 220.0, '44.5': 220.0, '45': 220.0, '45.5': 290.0, '46': 225.0, '47': 300.0, '47.5': 265.0, '48': 287, '48.5': 275.0, '49': 386, '49.5': 567, '50.5': 850, '51.5': 399}
1 голос
/ 25 апреля 2020

Вы можете сделать это с пониманием словаря, объединив два словаря с минимальным значением общих ключей:

{ **x, **y, **{k:min(x[k],y[k]) for k in x if k in y} }

вывод:

{'45': 220.0, '43': 220.0, '44.5': 220.0, '39': 370.0, '47': 300.0, '46': 225.0, '44': 220.0, '47.5': 265.0, '40.5': 395.0, '42.5': 230.0, '42': 300.0, '38': 375.0, '45.5': 290.0, '37.5': 355.0, '41': 345.0, '38.5': 375.0, '36': 345.0, '36.5': 360.0, '48.5': 275.0, '40': 380.0, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}

или вы можете написать его как это (чтобы избежать двойного слияния, когда большинство ключей являются общими):

{ **x, **{ k:v for k,v in y.items() if k not in x or x[k]<v} }

, или вы можете использовать сортировку по убыванию при конкатенации кортежей (ключ, значение), но сортировку данных целиком, чтобы получить минимум между соответствующими ключами будет очень неэффективно:

dict(sorted((*x.items(),*y.items()),key=lambda i:-i[1]))

Если вам не удобны словарные понимания, вы можете использовать простое для l oop:

merged = x.copy()
for k,v in y.items(): merged[k] = min(v, merged.get(k,v))
0 голосов
/ 25 апреля 2020

Вы можете использовать **kwargs для объединения словарей, поскольку оно расширяет содержимое словаря как набор пар ключ-значение. И мы можем сделать сравнение с keys, имеющими несколько value s в результирующем словаре,

import ast    

def compare_prices(dict1, dict2):
    temp1 = ast.literal_eval(dict1)
    temp2 = ast.literal_eval(dict2)
    tempDict = {**temp1, **temp2}   # two or more Dicts merged using **kwargs
    for key, value in tempDict.items():
        if key in temp1 and key in temp2:
            tempDict[key] = min([value, temp1[key]])    # sets the minimum value

    return tempDict 

Выходные данные ,

print(compare_prices(x, y))
#{'45': 220.0, '43': 220.0, '44.5': 220.0, '39': 370.0, '47': 300.0, '46': 225.0, '44': 220.0, '47.5': 265.0, '40.5': 395.0, '42.5': 230.0, '42': 300.0, '38': 375.0, '45.5': 290.0, '37.5': 355.0, '41': 345.0, '38.5': 375.0, '36': 345.0, '36.5': 360.0, '48.5': 275.0, '40': 380.0, '48': 287, '49.5': 567, '50.5': 850, '51.5': 399, '49': 386}

Если Вы хотите отсортированный словарь, который вы можете использовать OrderedDict из collections библиотеки

import ast
from collections import OrderedDict

def compare_prices(dict1, dict2):
    temp1 = ast.literal_eval(dict1)
    temp2 = ast.literal_eval(dict2)
    tempDict = {**temp1, **temp2}   # two or more Dicts merged using **kwargs
    for key, value in tempDict.items():
        if key in temp1 and key in temp2:
            tempDict[key] = min([value, temp1[key]])    # sets the minimum value

    return OrderedDict(sorted(tempDict.items(), key=lambda t: t[0]))

Вывод ,

print(compare_prices(x, y))
#OrderedDict([('36', 345.0), ('36.5', 360.0), ('37.5', 355.0), ('38', 375.0), ('38.5', 375.0), ('39', 370.0), ('40', 380.0), ('40.5', 395.0), ('41', 345.0), ('42', 300.0), ('42.5', 230.0), ('43', 220.0), ('44', 220.0), ('44.5', 220.0), ('45', 220.0), ('45.5', 290.0), ('46', 225.0), ('47', 300.0), ('47.5', 265.0), ('48', 287), ('48.5', 275.0), ('49', 386), ('49.5', 567), ('50.5', 850), ('51.5', 399)])
...