【问题标题】:How to compare two elements of a list to find lowest price?如何比较列表的两个元素以找到最低价格?
【发布时间】:2020-01-31 22:44:59
【问题描述】:

给定两个列表availprod,其中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']
]

【问题讨论】:

  • 请提供示例输入和输出,以帮助您的问题更清晰
  • 第一步是将您的两个列表合并为一个。那么确实min 应该立即返回正确的值。
  • @G.Anderson Done 添加了示例案例
  • @usr2564301 那会怎样呢?我想返回一个列表列表,其中包含列表列表中每个列表的价格、项目代码、电话号码。所以每个项目一个

标签: python algorithm list


【解决方案1】:

这是一个答案,在 cmets 中有解释:

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()]

【讨论】:

  • 请注意,您可以轻松更改生成的子列表中的内容,方法是移动元素或将其中一些元素排除在外、偏好问题以及您需要列表的目的。
【解决方案2】:

简单,清晰且非常pythonic解决您的问题。

我假设价格总是在avail 列表中的最后一个位置,而商品代码总是在availprod 列表中的第一个位置。这很明显,但要注意列表的元素顺序。

解决方案:

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']

免责声明:在您的代码中使用这样的单行代码可能不是一个好主意。

【讨论】:

  • @MattTheWizard 在我发布答案后更改了他的问题(列表元素的顺序已更改),因此我更新了我的答案。
【解决方案3】:

我能给你的第一个建议是为变量使用有意义的名称。

考虑到这一点,这是我提出的解决方案:

# 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': {}}

上面的代码以“先见先得”的逻辑处理关系。这意味着如果有两个vendors 与相同的vendor_product_price 对应相同的vendor_product_code,则看到的第一个vendor 会出现在报告中。

要将这种行为更改为 “最后一次看到,最后一次获胜”,请将比较行中的 &gt; 替换为 &gt;=,内容如下:

if prices[product_code]['price'] &gt; vendor_product_price:

最后,另一个策略是基于vendor_product_price 去重复vendors,保持最低价格,然后将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

还有很大的改进空间,但这是故意留下的。我愿意说教,而不是高效。

【讨论】:

    猜你喜欢
    • 2012-05-22
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2019-12-07
    • 2015-12-16
    • 1970-01-01
    相关资源
    最近更新 更多