Python-将字典值列表缩减为较小的列表

Python-将字典值列表缩减为较小的列表,python,dictionary,big-o,Python,Dictionary,Big O,我有一本字典,它的ID是配方ID,值是成分列表: recipe_dictionary = { 134: ['salt', 'chicken', 'tomato paste canned'], 523: ['toast whole grain', 'feta cheese' 'egg', 'salt'], 12: ['chicken', 'rice', 'parsley']} 我还有一个静态列表,其中

我有一本字典,它的ID是配方ID,值是成分列表:

recipe_dictionary  = { 134: ['salt', 'chicken', 'tomato paste canned'],
                       523: ['toast whole grain', 'feta cheese' 'egg', 'salt'], 
                       12: ['chicken', 'rice', 'parsley']}
我还有一个静态列表,其中包含我不想在白天重复的成分:

non_repeatable_ingredients = ['egg', 'chicken', 'beef']
现在我检查字典的每个值,然后循环检查成分名称,将每个名称与不可重复的成分列表进行比较,然后创建一个共享单词列表。因此,我的缩小字典看起来像:

   reduced_recipe_dictionary  = { 134: ['chicken'],
                                  523, ['egg'], 
                                  12: ['chicken']
这个过程需要很长时间,因为我真正的字典和配料表都很长。有没有比下面的方法更快的方法

这是减少膳食计划的方法:

reduced_meal_plans_dictionary = {}

# For each recipe
for recipe in meal_plans_dictionary:

    # Temp list for overlapp ingredients found for each recipe
    overlapped_ingredients_list = []

    # For each complete name of ingredient in the recipe
    for ingredient_complete_name in meal_plans_dictionary[recipe]:

        # Clean up the ingredient name as it sometimes involves comma, parentheses or spaces
        ingredient_string = ingredient_complete_name.replace(',', '').replace('(', '').replace(')', '').lower().strip()

        # Compare each ingredient name against the list of ingredients that shall not repeated in a day
        for each in PROTEIN_TAGS:

            # Compute the partial similarity
            partial_similarity = fuzz.partial_ratio(ingredient_string, each.lower())

            # If above 90, means one of the ingredients in the PROTEIN_TAGS exists in this recipe
            if partial_similarity > 90:
                # Make a list of such ingredients for this recipe
                overlapped_ingredients_list.append(each.lower())

    # Place the recipe ID as the key and the reduced overlapped list as the value
    reduced_meal_plans_dictionary[recipe] = overlapped_ingredients_list
我使用替换和相似性比率,因为成分名称不像我的示例那样干净;例如,我可以把鸡蛋或煮鸡蛋作为一种配料


谢谢。

既然每个食谱都有独特的成分,而且顺序也不重要,那么使用集合而不是列表怎么样

集合可以在O(1)固定时间内搜索,而列表可以在O(n)时间内搜索

例如:

recipe_dictionary = { 
    134: set(['salt', 'chicken', 'tomato paste canned']),
    523: set(['toast whole grain', 'feta cheese' 'egg', 'salt']), 
    12: set(['chicken', 'rice', 'parsley'])
}

non_repeatable_ingredients = set(['egg', 'chicken', 'beef'])
您可以在这样的集合中测试元素的存在性:

for ingredient in recipe_dictionary[134]:
    if ingredient in non_repeatable_ingredients:
        # do something

使用正则表达式和defaultdict的组合,您可以得到您想要的东西。这种方法使用regex来减少所需的
循环的
数量

注意,我已经调整了键
12
,以显示它将获得两个匹配项

recipe_dictionary  = { 134: ['salt', 'chicken', 'tomato paste canned'],
                        523: ['toast whole grain', 'feta cheese', 'egg', 'salt'],
                        12: ['whole chicken', 'rice', 'parsley', 'egg']}
non_repeatable_ingredients = ['egg', 'chicken', 'beef']
non_repeat = '(' + '|'.join(non_repeatable_ingredients) + ')'

d = defaultdict(list)
for k, j in recipe_dictionary.items():
     for i in j:
            m = re.search(non_repeat, i)
            if m:
                d[k].append(m.groups()[0])
d
defaultdict(list, {134: ['chicken'], 523: ['egg'], 12: ['chicken', 'egg']})
如果您没有与
不可重复的\u成分
列表中的项目匹配的干净成分,您可以使用
fuzzyfuzzy
模块中的
fuzz.partial\u ratio
来获得与之匹配的成分(比率大于80%的成分)。请先安装fuzzyfuzzy
然后再安装

>>> from fuzzywuzzy import fuzz
>>> reduced_recipe_dictionary = {k: list(filter(lambda x: fuzz.partial_ratio(v,x) >80, non_repeatable_ingredients)) for k,v in recipe_dictionary.items()}
>>> reduced_recipe_dictionary
{134: ['chicken'], 523: ['egg'], 12: ['chicken']}

是的,把你的配料改成字典而不是列表。然后你的匹配键不会搜索数组。谢谢你,罗布。这可能是一个很好的方法,如果我可以把不可重复的成分列表也做成一个字典,但我不能这样做,我现在也不能手工制作,因为成分列表很长。为什么不可重复的成分不能成为一个字典呢?因为我们有多个名称,即使是对于一个成分-它在Q中解释过。如果你想保持模糊匹配OP usedAh,添加一个完整的实现可能会很好,你是对的!非常感谢。今晚我将编辑我的回复。同样,配方字典中的成分名称与不可重复成分中的成分名称非常不同;这就是为什么我清理了这些名字,然后按相似性比率计算。我不能简单地使用>>如果非重复成分中的成分:@fatima我理解。尽管如此,使用集合要比使用列表快得多。@allardbrain,没错。我试着看看我是否能使用set。谢谢。如果我对所有配料都有完全相同的名称,那么这三个答案都会起作用。正如我在问题中提到的,它们与我的示例不一样,也不干净,所以我清理名称并使用相似性比率。谢谢你,法蒂玛。更新了我的答案,使之也能与密切匹配的成分一起工作@Sunitha Hi,这正是我所使用的:部分比例。谢谢。@Sunitha-我对你的答案投了赞成票-但我已经有了这个部分-它在我的Q中。W Stokvis回答了我的Q,我用了那个,所以我接受了它,但谢谢你的跟进。这确实有效。非常感谢。我的意思是,我现在确实得到了简化字典,我担心它需要很长时间,因为for循环。我有3个,这一个有2个嵌套for循环,所以我将尝试这个,并计时,看看它是否比我当前的方法快。谢谢。我测试了这个方法,速度快多了,谢谢。@fatima没问题。通过使用regex,您可以循环使用一次成分并检查匹配项,而不是每次循环使用每个
不可重复的成分。
>>> from fuzzywuzzy import fuzz
>>> reduced_recipe_dictionary = {k: list(filter(lambda x: fuzz.partial_ratio(v,x) >80, non_repeatable_ingredients)) for k,v in recipe_dictionary.items()}
>>> reduced_recipe_dictionary
{134: ['chicken'], 523: ['egg'], 12: ['chicken']}