Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq, where entity property contains another list

Tags:

c#

linq

I have two list:

List of strings:

var keywords = _db.KeyWords.Select(k => k.Word);

and list of objects:

var articles = _db.Articles;

What I want to achieve is to filter articles where article properties contains keywords, for example:

var model = articles.Where(a => a.Title.Contains(keywords) || a.Description.Contains(keywords));

Is possible in one query without foreach loop?

One solution is :

 List<Article> model = new List<Article>();
 foreach (var keyword in keywords)
 {
     model.AddRange(articles.Where(a => a.Title.Contains(keyword) || a.Description.Contains(keyword)));
 }

But i have 100 keywords, and it is heavy process using foreach loop.

like image 712
Nika Javakhishvili Avatar asked Jan 07 '23 01:01

Nika Javakhishvili


2 Answers

In words, you need to take only those items which have any word from keywords. So, in LINQ it can be done with something like:

var model = articles
    .Where(a => keywords.Any(k => a.Title.Contains(k) || a.Description.Contains(k)))
    .ToList();

If title or description does not contain any word from keywords, then it will not be added in the resulted list.

Note that it will not improve time complexity compared with foreach, but it may improve readbility.
In general, any algorithm iterating through all the keywords and articles, is going to take approximately Number of articles * Number of keywords * Average length of article operations, which grows pretty fast when variables grow. Keep it in mind.

like image 98
Yeldar Kurmangaliyev Avatar answered Jan 14 '23 17:01

Yeldar Kurmangaliyev


You can do this using the Any extension method.

For your solution:

var model = articles
           .Where(a => !keywords.Any(k => a.Title.Contains(k) || a.Description.Contains(k)))
           .ToList();

Here is a basic example to understand the method:

public class Person
{
    public string Name { get; set; }
    public string Pet { get; set; }
}

List<string> animals = new List<string>();
animals.Add("donkey");
animals.Add("horse");

List<Person> people = new List<Person>();
people.Add(new Person()
{
    Name = "Marco",
    Pet = "horse"
});
people.Add(new Person()
{
    Name = "John",
    Pet = "donkey"
});
people.Add(new Person()
{
    Name = "Penny",
    Pet = "dog"
});

//result will only include people who have pets that are in the animal list.
var res = people.Where(p => animals.Any(a => p.Pet.Contains(a)));

foreach (var item in res)
{
    Console.WriteLine("{0}-{1}", item.Name, item.Pet);
}

Console.ReadLine();
like image 43
EaziLuizi Avatar answered Jan 14 '23 19:01

EaziLuizi