python - 迭代命名元组列表,选择餐厅

标签 python list python-3.x namedtuple

我有一个函数可以返回价格等于或低于指定值的餐厅。这是我当前的代码:

Restaurant = namedtuple('Restaurant', 'name cuisine phone menu')
Dish = namedtuple('Dish', 'name price calories')

r1 = Restaurant('Thai Dishes', 'Thai', '334-4433', [Dish('Mee Krob', 12.50, 500),
                                                Dish('Larb Gai', 11.00, 450)])
r2 = Restaurant('Taillevent', 'French', '01-44-95-15-01', 
            [Dish('Homard Bleu', 45.00, 750),
             Dish('Tournedos Rossini', 65.00, 950),
             Dish("Selle d'Agneau", 60.00, 850)])


collection =[r1,r2]


def Collection_is_cheap(C, price):
    result = []
    if not C:
       return ''
    else:
        for rest in C:
            for dish in rest.menu:
                if dish.price <= price:
                    result.append(rest)
    return result

但是当我尝试运行它时:

print(Collection_is_cheap(collection, 28))

我得到了一长串正确的餐厅,但重复了。

[Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450)]), Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450)]), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=[Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)]), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=[Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)]), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=[Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)]), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=[Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)])]

而对于正确的输出,它应该只打印两家餐厅一次。我该如何纠正这个问题,以便该函数只返回:

[Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450)]), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=[Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)]

最佳答案

当你有一场比赛时,就停止循环浏览餐厅菜单;为此使用 break:

def Collection_is_cheap(C, price):
    result = []
    for rest in C:
        for dish in rest.menu:
            if dish.price <= price:
                result.append(rest)
                break  # stop the rest.menu loop, go to the next
    return result

请注意,我删除了 if not C: return '' 部分;最好不要从函数返回不同类型的对象。

演示:

>>> def Collection_is_cheap(C, price):
...     result = []
...     for rest in C:
...         for dish in rest.menu:
...             if dish.price <= price:
...                 result.append(rest)
...                 break  # stop the rest.menu loop, go to the next
...     return result
... 
>>> print(Collection_is_cheap(collection, 28))
[Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=(Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450))), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=(Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)))]

另一种方法是使用集合而不是列表;集合只能保存唯一的对象,因此多次添加餐厅不会产生任何效果:

def Collection_is_cheap(C, price):
    result = set()
    for rest in C:
        for dish in rest.menu:
            if dish.price <= price:
                result.add(rest)
    return list(result)

为此,您还需要使菜单使用元组,而不是列表:

r1 = Restaurant('Thai Dishes', 'Thai', '334-4433', (
    Dish('Mee Krob', 12.50, 500),
    Dish('Larb Gai', 11.00, 450)))

r2 = Restaurant('Taillevent', 'French', '01-44-95-15-01', ( 
    Dish('Homard Bleu', 45.00, 750),
    Dish('Tournedos Rossini', 65.00, 950),
    Dish("Selle d'Agneau", 60.00, 850)))

r3 = Restaurant('Pascal', 'French', '940-752-0107', (
    Dish('Escargots', 12.95, 250),
    Dish('Poached salmon', 18.50, 550),
    Dish("Rack of lamb", 24.00, 850),
    Dish("Marjolaine cake", 8.50, 950)))

因此它们是完全不可变的,这是使用集合的要求。

使用集合仅收集唯一餐馆的另一个影响是,返回的餐馆的顺序可能会改变,因为集合是无序的。相反,它们以依赖于实现的顺序保存对象,这有利于有效地测试已经存在的对象。

演示;对于这个只有两家廉价餐馆的简单示例,订单恰好与第一个版本返回的订单匹配:

>>> def Collection_is_cheap(C, price):
...     result = set()
...     for rest in C:
...         for dish in rest.menu:
...             if dish.price <= price:
...                 result.add(rest)
...     return list(result)
... 
>>> print(Collection_is_cheap(collection, 28))
[Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=(Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450))), Restaurant(name='Pascal', cuisine='French', phone='940-752-0107', menu=(Dish(name='Escargots', price=12.95, calories=250), Dish(name='Poached salmon', price=18.5, calories=550), Dish(name='Rack of lamb', price=24.0, calories=850), Dish(name='Marjolaine cake', price=8.5, calories=950)))]

如果您无法对菜单序列使用元组,并且由于某种原因无法使用 break 技巧,则每次都必须使用(缓慢且昂贵的)列表成员资格测试:

def Collection_is_cheap(C, price):
    result = []
    for rest in C:
        for dish in rest.menu:
            if dish.price <= price and rest not in result:
                result.append(rest)
    return result

这很慢而且成本很高,因为 Python 将分别测试列表中的每个元素以查看 rest == element 是否为 true,而对于集合,则使用称为哈希表的技巧> 用于快速检查对象是否已经存在,通常只需要一次计算检查。

关于python - 迭代命名元组列表,选择餐厅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31634825/

相关文章:

python - BaggingClassifier 在不同的执行中给出相同的结果

python - 分析和取消wave文件的常用频率

python - 是否有一个版本的 __file__ 在函数中使用时会获取使用该库的文件的名称?

java - 使用Swing的JList

java - 如何在java中使用列表中的数组

python - 如何定位要销毁的 tkinter 根窗口?

python - conda 无法创建环境

python - Cython,有没有办法创建只有一种类型的列表? (与 Python 列表不同)

python - PyQt5 动画行为作为类属性

python-3.x - 如何计算直方图的标准偏差? (Python,Matplotlib)