简体   繁体   中英

C# How to match all items in an array to list of search terms

I have a Recipe class:

public class Recipe
{
    public string Id { get; set; }
    public string RecipeTitle { get; set; }
    public string ChefName { get; set; }
    public List<string> HashTags { get; set; }
    public string Ingredients { get; set; }
}

The user can input a list of search terms into a search box and I want to return the recipes that match ALL of the search terms. Here is my code so far:

public Recipe[] SearchRecipes(string[] searchTerms, Recipe[] recipes)
{
    var matches = new List<Recipe>();

    foreach (var recipe in recipes)
    {

        if (searchTerms.Contains(recipe.ChefName, StringComparer.OrdinalIgnoreCase))
        {
            matches.Add(recipe);
        }

        foreach (var tag in recipe.Hashtags)
        {
            if (searchTerms.Contains(tag, StringComparer.OrdinalIgnoreCase))
            {
                matches.Add(recipe);
            }
        }

        foreach (var title in recipe.RecipeTitle)
        {
            if (searchTerms.Contains(title, StringComparer.OrdinalIgnoreCase))
            {
                matches.Add(recipe);
            }
        }
    }

    return matches.Distinct().ToArray();
}

However, this returns items that only match one or two of the criteria. Eg If the user searches "Chef Jane" and "Difficult" it will return also things from "Chef Callum" because the 'difficult' hashtag is present.

How can I make sure that the only ones returned are the complete matches?

I'm not sure what's the logic to traverse through the ingredients in that string, maybe you should make those a list as well. Anyway, you could create an array of recipe search terms for each recipe and return all the recipes where all the user input search terms are covered with those recipe search terms.

public Recipe[] SearchRecipes(string[] searchTerms, Recipe[] recipes)
{
    var matches = new List<Recipe>();

    foreach (var recipe in recipes)
    {
        // Just flattening all the hash tags together with other recipe search terms
        var recipeTerms = recipe.HashTags
            .Concat(new string[]
            {
                recipe.RecipeTitle,
                recipe.ChefName,
                recipe.Ingredients
            });

        // Will include only the recipes where all search terms are matched in recipe terms
        if (searchTerms.All(searchTerm =>
                recipeTerms.Contains(searchTerm, StringComparer.OrdinalIgnoreCase))
        {
            matches.Add(recipe);
        }
    }

    return matches.ToArray();
}

You could do the All logic manually as well, but it's simpler this way. It comes from the System.Linq namespace and you can take a look at its documentation here .

Complete LINQ solution would look something like this:

public Recipe[] SearchRecipes(string[] searchTerms, Recipe[] recipes)
    => recipes.Where(recipe =>
        {
            var recipeTerms = recipe.HashTags
                .Concat(new string[]
                {
                    recipe.RecipeTitle,
                    recipe.ChefName,
                    recipe.Ingredients
                });

            return searchTerms.All(searchTerm =>
                recipeTerms.Contains(searchTerm, StringComparer.OrdinalIgnoreCase));
        })
        .ToArray();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM