Machine Coding Problem

Food Recipe App

macoAlllifestyleunit-conversionfiltering
Commonly Asked By:YummlyTastyPinterest

Functional Scope (In-Scope)

  • Ingredient Density Unit Conversion: Converts fluid volume into metric weight utilizing dynamic density tables (e.g. converting sugar, flour, and milk accurately).
  • Dynamic Servings Scaling Engine: Adjusts raw volume metrics based on target-to-base ratio and performs decimal fraction formatting.
  • Dietary Tag Classification Matching: Restricts options strictly by filtering against specific dietary profiles (e.g. Vegetarian, Vegan, Gluten-Free).
  • Ingredient Overlap Recommendation Scoring: Analyzes a user's local pantry list to sort matching recipes by matching ratios.

Explicit Boundaries (Out-of-Scope)

  • Direct Grocery Order Delivery Integrations: Ignores external merchant APIs, payment checkouts, and routing logistics.
  • Active Recipe Social Sharing Boards: Excludes live user forums, comment systems, or photo attachment storage grids.

Production reference implementations demonstrating ingredient density translations and recipe scaling in Java and Python:

// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

enum Unit {
    GRAMS("Weight", 1.0),
    KILOGRAMS("Weight", 1000.0),
    MILLILITERS("Volume", 1.0),
    LITERS("Volume", 1000.0),
    CUPS("Volume", 240.0),
    TABLESPOON("Volume", 15.0),
    TEASPOON("Volume", 5.0);

    private final String type;
    private final double baseFactor; // Factor to convert to base unit (Grams or Milliliters)

    Unit(String type, double baseFactor) {
        this.type = type;
        this.baseFactor = baseFactor;
    }

    public String getType() { return type; }
    public double getBaseFactor() { return baseFactor; }
}

enum DietaryTag {
    VEGETARIAN, VEGAN, GLUTEN_FREE, KETO, NUT_FREE
}

class Ingredient {
    private final String name;
    private final double quantity;
    private final Unit unit;

    public Ingredient(String name, double quantity, Unit unit) {
        this.name = name;
        this.quantity = quantity;
        this.unit = unit;
    }

    public String getName() { return name; }
    public double getQuantity() { return quantity; }
    public Unit getUnit() { return unit; }

    @Override
    public String toString() {
        return String.format("%.2f %s of %s", quantity, unit, name);
    }
}

class Recipe {
    private final String recipeId;
    private final String title;
    private final int baseServings;
    private final List<Ingredient> ingredients;
    private final List<String> instructions;
    private final Set<DietaryTag> dietaryTags;

    public Recipe(String recipeId, String title, int baseServings, List<Ingredient> ingredients, List<String> instructions, Set<DietaryTag> dietaryTags) {
        this.recipeId = recipeId;
        this.title = title;
        this.baseServings = baseServings;
        this.ingredients = ingredients;
        this.instructions = instructions;
        this.dietaryTags = dietaryTags;
    }

    public String getRecipeId() { return recipeId; }
    public String getTitle() { return title; }
    public int getBaseServings() { return baseServings; }
    public List<Ingredient> getIngredients() { return ingredients; }
    public List<String> getInstructions() { return instructions; }
    public Set<DietaryTag> getDietaryTags() { return dietaryTags; }

    @Override
    public String toString() {
        return "Recipe{title='" + title + "', tags=" + dietaryTags + "}";
    }
}

class UnitConverter {
    // Density table for cross-family conversions: IngredientName -> Density (grams per milliliter)
    private static final Map<String, Double> densities = new HashMap<>();

    static {
        densities.put("flour", 0.53);  // 0.53g per ml
        densities.put("sugar", 0.84);  // 0.84g per ml
        densities.put("milk", 1.03);   // 1.03g per ml
        densities.put("water", 1.00);  // 1.00g per ml
    }

    public static Ingredient convert(Ingredient ingredient, Unit targetUnit) {
        if (ingredient.getUnit() == targetUnit) {
            return ingredient;
        }

        double val = ingredient.getQuantity();
        Unit sourceUnit = ingredient.getUnit();
        String name = ingredient.getName().toLowerCase();

        // 1. Convert within the same family (e.g. Weight -> Weight)
        if (sourceUnit.getType().equals(targetUnit.getType())) {
            double valueInBase = val * sourceUnit.getBaseFactor();
            double targetValue = valueInBase / targetUnit.getBaseFactor();
            return new Ingredient(ingredient.getName(), targetValue, targetUnit);
        }

        // 2. Cross-family conversion using density (Volume <-> Weight)
        double density = densities.getOrDefault(name, 1.0); // Fallback density
        double volumeInMl;

        if ("Weight".equals(sourceUnit.getType())) {
            // Weight to Volume: grams / density = ml
            double grams = val * sourceUnit.getBaseFactor();
            volumeInMl = grams / density;
        } else {
            // Volume to Weight: ml * density = grams
            double ml = val * sourceUnit.getBaseFactor();
            volumeInMl = ml * density; // This is weight in grams
        }

        // Convert base value of destination family to target unit
        double targetVal = volumeInMl / targetUnit.getBaseFactor();
        return new Ingredient(ingredient.getName(), targetVal, targetUnit);
    }
}

class RecipeService {
    private final List<Recipe> recipes = new CopyOnWriteArrayList<>();

    public void addRecipe(Recipe recipe) {
        recipes.add(recipe);
    }

    public List<Ingredient> scaleRecipe(Recipe recipe, int targetServings) {
        double ratio = (double) targetServings / recipe.getBaseServings();
        return recipe.getIngredients().stream()
                .map(i -> new Ingredient(i.getName(), roundToSensibleFraction(i.getQuantity() * ratio), i.getUnit()))
                .collect(Collectors.toList());
    }

    private double roundToSensibleFraction(double value) {
        return Math.round(value * 100.0) / 100.0;
    }

    // Pantry matching score resolver
    public List<Recipe> findRecipesByIngredients(Set<String> availableIngredients, Set<DietaryTag> dietaryFilters) {
        Set<String> lowerAvailable = availableIngredients.stream()
                .map(String::toLowerCase)
                .collect(Collectors.toSet());

        return recipes.stream()
                .filter(r -> r.getDietaryTags().containsAll(dietaryFilters))
                .sorted((r1, r2) -> {
                    double score1 = getMatchScore(r1, lowerAvailable);
                    double score2 = getMatchScore(r2, lowerAvailable);
                    return Double.compare(score2, score1); // Descending score
                })
                .collect(Collectors.toList());
    }

    private double getMatchScore(Recipe recipe, Set<String> lowerAvailable) {
        if (recipe.getIngredients().isEmpty()) return 0.0;
        
        long matches = recipe.getIngredients().stream()
                .map(i -> i.getName().toLowerCase())
                .filter(lowerAvailable::contains)
                .count();

        return (double) matches / recipe.getIngredients().size();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("=== STARTING FOOD RECIPE APP SIMULATION ===");
        RecipeService service = new RecipeService();

        // Create mock recipes
        List<Ingredient> cakeIngredients = List.of(
            new Ingredient("flour", 2.0, Unit.CUPS),
            new Ingredient("sugar", 200.0, Unit.GRAMS),
            new Ingredient("milk", 1.0, Unit.CUPS)
        );
        Recipe sweetCake = new Recipe("r1", "Sweet Cake", 4, cakeIngredients, List.of("Mix", "Bake"), Set.of(DietaryTag.VEGETARIAN));

        List<Ingredient> breadIngredients = List.of(
            new Ingredient("flour", 3.0, Unit.CUPS),
            new Ingredient("water", 1.5, Unit.CUPS)
        );
        Recipe veganBread = new Recipe("r2", "Vegan Bread", 6, breadIngredients, List.of("Knead", "Rise", "Bake"), Set.of(DietaryTag.VEGETARIAN, DietaryTag.VEGAN, DietaryTag.NUT_FREE));

        service.addRecipe(sweetCake);
        service.addRecipe(veganBread);

        // 1. Density-based conversion testing
        System.out.println("--- Density-Based Converter Test ---");
        Ingredient sugarInCups = new Ingredient("sugar", 2.0, Unit.CUPS);
        Ingredient sugarInGrams = UnitConverter.convert(sugarInCups, Unit.GRAMS);
        System.out.println("2 Cups of Sugar converted to Grams: " + sugarInGrams); // Uses density: 2 * 240 * 0.84 = 403.2g

        Ingredient milkInGrams = new Ingredient("milk", 500.0, Unit.GRAMS);
        Ingredient milkInCups = UnitConverter.convert(milkInGrams, Unit.CUPS);
        System.out.println("500g of Milk converted to Cups: " + milkInCups); // Uses density

        // 2. Scaling recipe servings
        System.out.println("\n--- Recipe Ingestion Scaling Test ---");
        System.out.println("Scaling Sweet Cake from 4 servings to 12 servings:");
        List<Ingredient> scaled = service.scaleRecipe(sweetCake, 12);
        for (Ingredient ing : scaled) {
            System.out.println("  " + ing);
        }

        // 3. Pantry Match Matching Test
        System.out.println("\n--- Pantry-based Match Ranking ---");
        Set<String> pantry = Set.of("flour", "water");
        System.out.println("Searching vegetarian recipes matching pantry items: " + pantry);
        List<Recipe> matched = service.findRecipesByIngredients(pantry, Set.of(DietaryTag.VEGETARIAN));
        for (Recipe r : matched) {
            System.out.println("  Matched Recipe: " + r.getTitle());
        }

        System.out.println("=== FOOD RECIPE APP SIMULATION COMPLETE ===");
    }
}