Nhyi
Nhyi

Reputation: 383

How to count the number of times a string appears in a dictionary value in Python?

So I have a dictionary that contains recipes. My current code is checking if a string exists in a value then add it to the counter. However I want it so that whenever the string is encountered in a dictionary value add one to the counter as there could be multiple occurrences of the same word in the value and I want to make sure I count all of them. Right now my code for counting the values in the dictionary is this:

        if (token in str(value).lower()) and (key == 'title'):
            title_c += 1
            
        elif (token in str(value).lower()) and (key == 'categories'):
            cat_c += 1
            
        elif (token in str(value).lower()) and (key == 'ingredients'):
            ing_c += 1
            
        elif (token in str(value).lower()) and (key == 'directions'):
            dire_c += 1

It checks the key for the dictionary and if the string appears in the value for that key and if it does add 1 to the counter. However if the token was 'banana' but the value for the title key for example was 'banana banana' it would add 1 to the title counter instead of 2. How could I change it for this?

My dictionary contains a list of recipes. Here is an example of a piece of data in the dictionary. My search is only looking through title, categories, ingredients and directions.

{
  "title": "\"Blanketed\" Eggplant ",
  "categories": [
   "Tomato",
   "Vegetable",
   "Appetizer",
   "Side",
   "Vegetarian",
   "Eggplant",
   "Pan-Fry",
   "Vegan",
   "Bon App\u00e9tit"
  ],
  "ingredients": [
   "8 small Japanese eggplants, peeled",
   "16 large fresh mint leaves",
   "4 large garlic cloves, 2 slivered, 2 flattened",
   "2 cups olive oil (for deep frying)",
   "2 pounds tomatoes",
   "7 tablespoons extra-virgin olive oil",
   "1 medium onion, chopped",
   "6 fresh basil leaves",
   "1 tablespoon dried oregano",
   "1 1/2 tablespoons drained capers"
  ],
  "directions": [
   "Place eggplants on double thickness of paper towels. Salt generously. Let stand 1 hour. Pat dry with paper towels. Cut 2 deep incisions in each eggplant. Using tip of knife, push 1 mint leaf and 1 garlic sliver into each incision.",
   "Pour 2 cups oil into heavy medium saucepan and heat to 375\u00b0F. Add eggplants in batches and fry until deep golden brown, turning occasionally, about 4 minutes. Transfer eggplants to paper towels and drain.",
   "Blanch tomatoes in pot of boiling water for 20 seconds. Drain. Peel tomatoes. Cut tomatoes in half; squeeze out seeds. Chop tomatoes; set aside.",
   "Heat 4 tablespoons extra-virgin olive oil in large pot over high heat. Add 2 flattened garlic cloves; saut\u00e9 until light brown, about 3 minutes. Discard garlic. Add onion; saut\u00e9 until translucent, about 5 minutes. Add reduced to 3 cups, stirring occasionally, about 20 minutes.",
   "Mix capers and 3 tablespoons extra-virgin olive oil into sauce. Season with salt and pepper. Reduce heat. Add eggplants. Simmer 5 minutes, spooning sauce over eggplants occasionally. Spoon sauce onto platter. Top with eggplants. Serve warm or at room temperature."
  ],
  "rating": 3.75,
  "calories": 1386.0,
  "protein": 9.0,
  "fat": 133.0
 },

{
  "title": "\"Bloody Mary\" Tomato Toast with Celery and Horseradish ",
  "categories": [
   "Condiment/Spread",
   "Tomato",
   "Appetizer",
   "Kid-Friendly",
   "Quick & Easy",
   "Lunch",
   "Spring",
   "Summer",
   "Vegetarian",
   "Dairy Free",
   "Peanut Free",
   "Tree Nut Free",
   "Soy Free",
   "Kosher"
  ],
  "ingredients": [
   "1 lemon, zested, juiced",
   "1/2 shallot, finely chopped",
   "1 pound grape tomatoes, halved",
   "2 tablespoons extra-virgin olive oil",
   "1 tablespoon Sherry vinegar",
   "1 teaspoon kosher salt",
   "1 teaspoon freshly ground black pepper",
   "1 teaspoon Worcestershire sauce",
   "1/4 teaspoon cayenne pepper",
   "5 tablespoons finely grated fresh horseradish, divided",
   "2 celery stalks, thinly sliced",
   "3 tablespoons coarsely chopped celery leaves",
   "6 tablespoons mayonnaise",
   "6 slices toasted rye bread"
  ],
  "directions": [
   "Combine lemon zest, lemon juice, shallot, tomatoes, oil, vinegar, salt, black pepper, Worcestershire sauce, cayenne, and 1 Tbsp. horseradish in a large bowl. Let marinate 10 minutes, then stir in celery stalks and leaves.",
   "Meanwhile, combine mayonnaise and remaining 4 Tbsp. horseradish in a small bowl. Spread 1 Tbsp. horseradish-mayonnaise on each slice of rye. Top toasts evenly with tomato mixture."
  ],
  "rating": 5.0,
  "calories": 189.0,
  "protein": 2.0,
  "fat": 16.0
 },

Upvotes: 0

Views: 2276

Answers (4)

jignatius
jignatius

Reputation: 6474

I think you want exact word matches? You could use re.findall for that with a regex and a defaultdict for counting the word occurrences.

from collections import defaultdict

keys = [ "title", "categories", "ingredients", "directions"]
token = 'oil'
count = defaultdict(int)

for key in keys:
    value = data[key]
    if isinstance(value, str):
        count[key] += len(re.findall(fr'\b{token}\b', value, flags=re.IGNORECASE))
    elif (isinstance(value, list)):
        count[key] += sum(len(re.findall(fr'\b{token}\b', line, flags=re.IGNORECASE)) for line in value)

print(count)

If you don't want to match against whole word, remove the word breaks (\b) from the regex.

Upvotes: 0

balderman
balderman

Reputation: 23815

see below

data = {
    "title": "\"Blanketed\" Eggplant ",
    "categories": [
        "Tomato",
        "Vegetable",
        "Appetizer",
        "Side",
        "Vegetarian",
        "Eggplant",
        "Pan-Fry",
        "Vegan",
        "Bon App\u00e9tit"
    ],
    "ingredients": [
        "8 small Japanese eggplants, peeled",
        "16 large fresh mint leaves",
        "4 large garlic cloves, 2 slivered, 2 flattened",
        "2 cups olive oil (for deep frying)",
        "2 pounds tomatoes",
        "7 tablespoons extra-virgin olive oil",
        "1 medium onion, chopped",
        "6 fresh basil leaves",
        "1 tablespoon dried oregano",
        "1 1/2 tablespoons drained capers"
    ],
    "directions": [
        "Place eggplants on double thickness of paper towels. Salt generously. Let stand 1 hour. Pat dry with paper towels. Cut 2 deep incisions in each eggplant. Using tip of knife, push 1 mint leaf and 1 garlic sliver into each incision.",
        "Pour 2 cups oil into heavy medium saucepan and heat to 375\u00b0F. Add eggplants in batches and fry until deep golden brown, turning occasionally, about 4 minutes. Transfer eggplants to paper towels and drain.",
        "Blanch tomatoes in pot of boiling water for 20 seconds. Drain. Peel tomatoes. Cut tomatoes in half; squeeze out seeds. Chop tomatoes; set aside.",
        "Heat 4 tablespoons extra-virgin olive oil in large pot over high heat. Add 2 flattened garlic cloves; saut\u00e9 until light brown, about 3 minutes. Discard garlic. Add onion; saut\u00e9 until translucent, about 5 minutes. Add reduced to 3 cups, stirring occasionally, about 20 minutes.",
        "Mix capers and 3 tablespoons extra-virgin olive oil into sauce. Season with salt and pepper. Reduce heat. Add eggplants. Simmer 5 minutes, spooning sauce over eggplants occasionally. Spoon sauce onto platter. Top with eggplants. Serve warm or at room temperature."
    ],
    "rating": 3.75,
    "calories": 1386.0,
    "protein": 9.0,
    "fat": 133.0
}
keys = {'ingredients', 'directions'}  # TODO: add more
counters = {k: 0 for k in keys}
token = 'eggplant'
for key in keys:
    cnt = 0
    for entry in data[key]:
        cnt += entry.count(token)
    counters[key] += cnt
print(counters)

output

{'ingredients': 1, 'directions': 7}

Upvotes: 0

Chris
Chris

Reputation: 16137

It looks to me like you have a list of dictionaries. If that's the case this should help. I've duplicated the recipe you posted and placed it into a list to demonstrate.

This will count the how many times every unique word appears in all of the categories you are interested in. Then you can just print the counter c with the token you are interested in, or print c by itself to see all of the counts.

from collections import Counter
from itertools import chain

recipe_dict = [{
  "title": "\"Blanketed\" Eggplant ",
  "categories": [
   "Tomato",
   "Vegetable",
   "Appetizer",
   "Side",
   "Vegetarian",
   "Eggplant",
   "Pan-Fry",
   "Vegan",
   "Bon App\u00e9tit"
  ],
  "ingredients": [
   "8 small Japanese eggplants, peeled",
   "16 large fresh mint leaves",
   "4 large garlic cloves, 2 slivered, 2 flattened",
   "2 cups olive oil (for deep frying)",
   "2 pounds tomatoes",
   "7 tablespoons extra-virgin olive oil",
   "1 medium onion, chopped",
   "6 fresh basil leaves",
   "1 tablespoon dried oregano",
   "1 1/2 tablespoons drained capers"
  ],
  "directions": [
   "Place eggplants on double thickness of paper towels. Salt generously. Let stand 1 hour. Pat dry with paper towels. Cut 2 deep incisions in each eggplant. Using tip of knife, push 1 mint leaf and 1 garlic sliver into each incision.",
   "Pour 2 cups oil into heavy medium saucepan and heat to 375\u00b0F. Add eggplants in batches and fry until deep golden brown, turning occasionally, about 4 minutes. Transfer eggplants to paper towels and drain.",
   "Blanch tomatoes in pot of boiling water for 20 seconds. Drain. Peel tomatoes. Cut tomatoes in half; squeeze out seeds. Chop tomatoes; set aside.",
   "Heat 4 tablespoons extra-virgin olive oil in large pot over high heat. Add 2 flattened garlic cloves; saut\u00e9 until light brown, about 3 minutes. Discard garlic. Add onion; saut\u00e9 until translucent, about 5 minutes. Add reduced to 3 cups, stirring occasionally, about 20 minutes.",
   "Mix capers and 3 tablespoons extra-virgin olive oil into sauce. Season with salt and pepper. Reduce heat. Add eggplants. Simmer 5 minutes, spooning sauce over eggplants occasionally. Spoon sauce onto platter. Top with eggplants. Serve warm or at room temperature."
  ],
  "rating": 3.75,
  "calories": 1386.0,
  "protein": 9.0,
  "fat": 133.0
 },
{
  "title": "\"Blanketed\" Eggplant ",
  "categories": [
   "Tomato",
   "Vegetable",
   "Appetizer",
   "Side",
   "Vegetarian",
   "Eggplant",
   "Pan-Fry",
   "Vegan",
   "Bon App\u00e9tit"
  ],
  "ingredients": [
   "8 small Japanese eggplants, peeled",
   "16 large fresh mint leaves",
   "4 large garlic cloves, 2 slivered, 2 flattened",
   "2 cups olive oil (for deep frying)",
   "2 pounds tomatoes",
   "7 tablespoons extra-virgin olive oil",
   "1 medium onion, chopped",
   "6 fresh basil leaves",
   "1 tablespoon dried oregano",
   "1 1/2 tablespoons drained capers"
  ],
  "directions": [
   "Place eggplants on double thickness of paper towels. Salt generously. Let stand 1 hour. Pat dry with paper towels. Cut 2 deep incisions in each eggplant. Using tip of knife, push 1 mint leaf and 1 garlic sliver into each incision.",
   "Pour 2 cups oil into heavy medium saucepan and heat to 375\u00b0F. Add eggplants in batches and fry until deep golden brown, turning occasionally, about 4 minutes. Transfer eggplants to paper towels and drain.",
   "Blanch tomatoes in pot of boiling water for 20 seconds. Drain. Peel tomatoes. Cut tomatoes in half; squeeze out seeds. Chop tomatoes; set aside.",
   "Heat 4 tablespoons extra-virgin olive oil in large pot over high heat. Add 2 flattened garlic cloves; saut\u00e9 until light brown, about 3 minutes. Discard garlic. Add onion; saut\u00e9 until translucent, about 5 minutes. Add reduced to 3 cups, stirring occasionally, about 20 minutes.",
   "Mix capers and 3 tablespoons extra-virgin olive oil into sauce. Season with salt and pepper. Reduce heat. Add eggplants. Simmer 5 minutes, spooning sauce over eggplants occasionally. Spoon sauce onto platter. Top with eggplants. Serve warm or at room temperature."
  ],
  "rating": 3.75,
  "calories": 1386.0,
  "protein": 9.0,
  "fat": 133.0
 }]

output = []
token = 'tomato'
for d in recipe_dict:
    output.extend([x.lower().split() for x in d['categories'] +  d['ingredients'] + d['directions']])
    
c = Counter(chain.from_iterable(output))

print(c[token])

Upvotes: 0

raidenace
raidenace

Reputation: 12826

You could try regular expressions like example below:

import re
value = "banana test banana"
token = "banana"
result = re.findall(token, value)
print(len(result))

Upvotes: 1

Related Questions