Как сравнить два элемента списка, чтобы найти самую низкую цену? - PullRequest
2 голосов
/ 01 февраля 2020

Учитывая два списка avail и prod, где avail - это список, содержащий номер телефона, код товара и цену, а prod - список, содержащий код и имя товара, я хочу попробовать и найдите самую низкую цену для данного кода товара, если код товара в avail также находится в prod (список продуктов), возвращая список списков, в котором указаны номер телефона, цена и код товара для каждого товара.

Я пробовал код ниже, но он просто добавляет каждый j[2] по понятным причинам (он добавляет все цены и просто печатает мин). Я не знаю, как это реализовать.

def best_prices(avail,prod):
    lowest_prices=[]
    price_list=[]
    for i in prod:
        for j in avail:
            if i[0]==j[1]:
                price_list.append(j[2])
                store_min=min(price_list)
                print(store_min)
                print(price_list)
                lowest_prices.append(j)
    return lowest_prices

Списки в этом формате:

avail = [
    ['phone number', 'item code', 'price'],
    ...
] 

prod = [
    ['item code', 'name of product'],
    ...
]

Вот несколько примеров ввода:

prod = [
    ['123456789', '2L 2% Vitali Milk'],
    ['123456798', '1L 2% Vitali Milk'],
    ['456392452', '70% Cocoa Zimbra Chocolate'],
    ['456123490', 'Zimbra Milk Chocolate'],
    ['634590221', 'Onion flavour chips'],
    ['634599011', 'Vinegar flavour chips'],
    ['780123678', 'Sliced white bread'],
    ['780432109', 'Sliced whole wheat bread'],
    ['809001234', '2L Orange Juice'],
    ['808765432', '2L Apple Juice']
]

avail = [
    ['123456789', '7807890123', '2.58'],
    ['123456789', '7804922860', '2.99'],
    ['456392452', '7807890123', '2.11'],
    ['456123490', '7804922860', '3.10'],
    ['808765432', '7809876543', '4.10']
]

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

Итак, для:

prod = [
    ['123456789', '2L 2% Vitali Milk']
]

и

avail = [
    ['123456789', '7807890123', '2.58'],
    ['123456789', '7804922860', '2.99'],
    ['456392452', '7807890123', '2.11']
]

Я хочу вернуть:

new_list = [
    ['2.58', '123456789', '7807890123']
]

Ответы [ 3 ]

1 голос
/ 01 февраля 2020

Вот ответ с объяснением в комментариях:

prod = [
    ['123456789', '2L 2% Vitali Milk'],
    ['123456798', '1L 2% Vitali Milk'],
    ['456392452', '70% Cocoa Zimbra Chocolate'],
    ['456123490', 'Zimbra Milk Chocolate'],
    ['634590221', 'Onion flavour chips'],
    ['634599011', 'Vinegar flavour chips'],
    ['780123678', 'Sliced white bread'],
    ['780432109', 'Sliced whole wheat bread'],
    ['809001234', '2L Orange Juice'],
    ['808765432', '2L Apple Juice']
]
avail = [
    ['123456789', '7807890123', '2.58'],
    ['123456789', '7804922860', '2.99'],
    ['456392452', '7807890123', '2.11'],
    ['456123490', '7804922860', '3.10'],
    ['808765432', '7809876543', '4.10']
]

# you can keep track of the best record for a given product code using a dict
result = {}

# since prod is really just a mapping from product code to product name, it 
# also works well as a dict
prod_d = {p[0]: p[1] for p in prod}

# now, it's easy to construct the result from avail:
# (the cast to tuple allows for spreading into nicely named variables)
for pc, phone, price in (tuple(a) for a in avail):
    # using -1 as price will still be the last element
    if pc not in result or price < result[pc][-1]:
        result[pc] = [prod_d[pc], phone, price]
print(result)

# if you prefer a list after all:
result = [[pc, prod, phone, price] for pc, (prod, phone, price) in result.items()]
print(result)

Результат:

{'123456789': ['2L 2% Vitali Milk', '7807890123', '2.58'], '456392452': ['70% Cocoa Zimbra Chocolate', '7807890123', '2.11'], '456123490': ['Zimbra Milk Chocolate', '7804922860', '3.10'], '808765432': ['2L Apple Juice', '7809876543', '4.10']}
[['123456789', '2L 2% Vitali Milk', '7807890123', '2.58'], ['456392452', '70% Cocoa Zimbra Chocolate', '7807890123', '2.11'], ['456123490', 'Zimbra Milk Chocolate', '7804922860', '3.10'], ['808765432', '2L Apple Juice', '7809876543', '4.10']]

Просто решение:

result = {}
prod_d = {p[0]: p[1] for p in prod}

for pc, phone, price in (tuple(a) for a in avail):
    if pc not in result or price < result[pc][-1]:
        result[pc] = [prod_d[pc], phone, price]

result_list = [[pc, prod, phone, price] for pc, (prod, phone, price) in result.items()]
1 голос
/ 01 февраля 2020

Первый совет, который я могу дать, - это использовать значимые имена для ваших переменных.

Имея это в виду, вот решение, которое я предлагаю:

# just for a nice output
from pprint import pprint


def find_best_prices(products, vendors):
    prices = {}

    for product_code, product_name in products:
        for vendor_product_code, vendor_phone, vendor_product_price in vendors:
            if product_code not in prices:
                prices[product_code] = {}
            if product_code == vendor_product_code:
                if prices[product_code]:
                    if prices[product_code]['price'] > vendor_product_price:
                        prices[product_code] = {
                            'vendor_price': vendor_product_price,
                            'vendor_phone': vendor_phone
                        }
                else:
                    prices[product_code] = {
                        'vendor_price': vendor_product_price,
                        'vendor_phone': vendor_phone
                    }

    return prices


products = [
    ['123456789', '2L 2% Vitali Milk'],
    ['123456798', '1L 2% Vitali Milk'],
    ['456392452', '70% Cocoa Zimbra Chocolate'],
    ['456123490', 'Zimbra Milk Chocolate'],
    ['634590221', 'Onion flavour chips'],
    ['634599011', 'Vinegar flavour chips'],
    ['780123678', 'Sliced white bread'],
    ['780432109', 'Sliced whole wheat bread'],
    ['809001234', '2L Orange Juice'],
    ['808765432', '2L Apple Juice']
]

vendors = [
    ['123456789', '7807890123', '2.58'],
    ['123456789', '7804922860', '2.99'],
    ['456392452', '7807890123', '2.11'],
    ['456123490', '7804922860', '3.10'],
    ['808765432', '7809876543', '4.10']
]

pprint(find_best_prices(products, vendors))

Приведенный выше код приведет к в следующем выводе:

{'123456789': {'vendor_phone': '7807890123', 'vendor_price': '2.58'},
 '123456798': {},
 '456123490': {'vendor_phone': '7804922860', 'vendor_price': '3.10'},
 '456392452': {'vendor_phone': '7807890123', 'vendor_price': '2.11'},
 '634590221': {},
 '634599011': {},
 '780123678': {},
 '780432109': {},
 '808765432': {'vendor_phone': '7809876543', 'vendor_price': '4.10'},
 '809001234': {}}

Приведенный выше код имеет дело с галстуками в «первый раз видел, первый выиграл» logi c. Это означает, что если есть два vendors с одним и тем же vendor_product_price для одного и того же vendor_product_code, в отчет попадает первый vendor.

Чтобы изменить это поведение на "last видно, последний выигрывает ", замените > на >= в строке сравнения, которая гласит:

if prices[product_code]['price'] > vendor_product_price:

И, наконец, другая стратегия будет лишена дубликатов vendors на основе vendor_product_price, сохраняя минимальную цену, а затем свяжите products с результирующим списком.

Вот реализация этой идеи:

def find_best_prices(products, vendors):
    prices = {}
    for product, phone, price in vendors:
        if product not in prices:
            prices[product] = {
                'vendor_phone': phone,
                'vendor_price': price
            }
        else:
            if prices[product]['vendor_price'] > price:
                prices[product] = {
                    'vendor_phone': phone,
                    'vendor_price': price
                }

    for product, _ in products:
        if product not in prices:
            prices[product] = {}

    return prices

Существует много возможностей для улучшения, но это было оставлено специально. Я хочу быть дидактическим c, не эффективным.

1 голос
/ 01 февраля 2020

Простое, понятное и довольно pythoni c решение вашей проблемы ниже.

Я сделал предположение, что цена всегда находится на последней позиции в списке avail, а код товара всегда на первой позиция в списках avail и prod. Это довольно очевидно, но будьте осторожны с порядком элементов списков.

Решение:

avail = [
    ['item code', 'phone number', 'price'],
    ...
]

prod = [
    ['item code', 'name of product'],
    ...
]

def best_prices(avail, prod):
    # find only items from available with item code present in products
    items = [
        av for av in avail if any(av[0] == pr[0] for pr in prod)
    ]
    # check if any item is available
    if not items:
       return None
    # sort items by price (ascending) and return first item
    return sorted(items, key=lambda x: x[2])[0]

Пример:

>>> prod = [
...     ['123456789', '2L 2% Vitali Milk'],
... ]
>>> avail = [
...     ['123456789', '7807890123', '2.58'],
...     ['123456789', '7804922860', '2.99'],
...     ['456392452', '7807890123', '2.11'],
... ]
>>> print(best_prices(avail, prod))
['123456789', '7807890123', '2.58']

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

def best_prices(avail, prod):
    ....
    return sorted(items, key=lambda x: x[2])[0][::-1]

Бонус:

Экстремальный однострочный, который работает точно так, как вы ожидаете, что он будет работать:

>>> print((sorted([a for a in avail if any(a[0] == p[0] for p in prod)], key=lambda x: x[2]) or [None])[0][::-1])
['2.58', '7807890123', '123456789']

Отказ от ответственности: вероятно, не стоит использовать такие однострочники в вашем коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...