LINQ: Entity string field contains any of an array of strings - linq

I want to get a collection of Product entities where the product.Description property contains any of the words in a string array.
It would look something like this (result would be any product which had the word "mustard OR "pickles" OR "relish" in the Description text):
Dim products As List(Of ProductEntity) = New ProductRepository().AllProducts
Dim search As String() = {"mustard", "pickles", "relish"}
Dim result = From p In products _
Where p.Description.Contains(search) _
Select p
Return result.ToList
I already looked at this similar question but couldn't get it to work.

Since you want to see if search contains a word which is contained in the description of p you basically need to test for each value in search if it is contained in the description of p
result = from p in products
where search.Any(val => p.Description.Contains(val))
select p;
This is c# syntax for the lambda method since my vb is not that great

Dim result = From p in products _
Where search.Any(Function(s) p.Description.Contains(s))
Select p

You can use a simple LINQ query, if all you need is to check for substrings:
var q = words.Any(w => myText.Contains(w));
// returns true if myText == "This password1 is weak";
If you want to check for whole words, you can use a regular expression:
Matching against a regular expression that is the disjunction of all the words:
// you may need to call ToArray if you're not on .NET 4
var escapedWords = words.Select(w => #"\b" + Regex.Escape(w) + #"\b");
// the following line builds a regex similar to: (word1)|(word2)|(word3)
var pattern = new Regex("(" + string.Join(")|(", escapedWords) + ")");
var q = pattern.IsMatch(myText);
Splitting the string into words with a regular expression, and testing for membership on the words collection (this will get faster if you use make words into a HashSet instead of a List):
var pattern = new Regex(#"\W");
var q = pattern.Split(myText).Any(w => words.Contains(w));
In order to filter a collection of sentences according to this criterion all you have to do its put it into a function and call Where:
// Given:
// bool HasThoseWords(string sentence) { blah }
var q = sentences.Where(HasThoseWords);
Or put it in a lambda:
var q = sentences.Where(s => Regex.Split(myText, #"\W").Any(w => words.Contains(w)));
Ans From => How to check if any word in my List<string> contains in text by #R. Martinho Fernandes

Related

Compare two comma separated strings and get count of intersecting values

What is the best code for comparing 2 comma separated strings and retrieving values that intersect? For instance lets say I have string "a,b,c" and the target string "x,b,y", I need result saying there is 1 occurrence.
As suggested here One way of doing this is
public static bool UserCanAccessThisPage(string userAccessGroups,
string pageItemAccessGroups)
{
return userAccessGroups.Split(',')
.Select(s => s.Trim())
.Contains(pageItemAccessGroups);
}
But this will only check the match but I do also need occurrences. Any suggestions please
Use Enumerable.Intersect to get intersection of two sequences:
var occurrences =
userAccessGroups.Split(',').Select(s => s.Trim())
.Intersect(pageItemAccessGroups.Split(',').Select(s => s.Trim()));
Checking if occurrences exist:
bool exist = occurrences.Any();
Getting occurrences count:
int count = occurrences.Count();
To make code more readable you can store groups in local variables:
// this can be ordinal named method
Func<string, IEnumerable<string>> parse =
csv => csv.Split(',').Select(s => s.Trim());
var userGroups = parse(userAccessGroups);
var pateItemGroups = parse(pageItemAccessGroups);
var occurrences = userGroups.Intersect(pageItemGroups);

How to get a list of the grouped values in linq groupby?

Linq newbie here, struggling with my first GroupBy query.
I have a list of objects of type KeywordInstance which represents a keyword, and the ID of the database record to which the keyword was applied.
Keyword RecordID
macrophages 1
macrophages 2
cell cycle 3
map kinase 2
cell cycle 1
What I want is a collection of all keywords, with a list of the RecordIDs to which each keyword was applied.
Keyword RecordIDs
macrophages 1, 2
cell cycle 1, 3
map kinase 2
I tried using Linq to get it into a new object. I only managed to get the distinct keywords.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key});
The problem is that I can't seem to get the values of g in any way. g is of the type IGrouping<String, KeywordInstance> and by documentation, it only has the property Key, but not even the property Value. All the examples I have seen on the Internet for groupby just tell me to select g itself, but the result of
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key, RecordIDs = g});
is not what I want.
Any try to get something out of g fails with the error message System.Linq.IGropuing<string, UserQuery.KeywordInstance> does not have a definition for [whatever I tried].
What am I doing wrong here?
I think you are close to you solution.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new
{
keyword = g.Key,
RecordIDs = g.Select(c => c.ID)
});
Just Select the records you need.
The reason you are seeing the Keyword-column as well as the ID-column, is becuase it's part of g
var keywords = allWords.GroupBy(w => w.keyword);
foreach (var itm in keywords)
{
var list = itm.ToList();
//list returns all of the original properties/values objects from allwords.
//itm.key returns w.keyword
}

how to use a dynamic variable in orderby clause

am a newbie in linq.. am stuck with one scenario. ie,
i have to sort the search results based on user input.
user inputs are Last Name, First Name and Title. for input 3 drop downs are there and i have to sort result based on the values selected.
i tried
order = Request["orders"].Split(',');
var param = order[0];
var p1 = typeof(Test).GetProperty(param);
param = order[1];
var p2 = typeof(Test).GetProperty(param);
param = order[2];
var p3 = typeof(Test).GetProperty(param);
model.Test = (from tests in model.Test
select tests).
OrderBy(x => p1.GetValue(x, null)).
ThenBy(x => p2.GetValue(x, null)).
ThenBy(x => p3.GetValue(x, null));
but it doesn't works.
i want qry like this
from tests in model.Test
select tests).OrderBy(x => x.lastname).
ThenBy(x => x.firstname).ThenBy(x => x.Title);
order[0]== lastname but how can i use it in the place of OrderBy(x => x.order[0])..?
Thanks in advance.
i solved my case as follows
// list of columns to be used for sorting
List<string>order = Request["orders"].Split(',').ToList();
//map the column string to property
var mapp = new Dictionary<string, Func<Test, string>>
{
{"FirstName", x => x.FirstName},
{"LastName", x => x.LastName},
{"SimpleTitle", x => x.SimpleTitle}
};
//user inputted order
var paras = new List<Func<Test, string>>();
foreach (var para in order)
{
if(!string.IsNullOrEmpty(para))
paras.Add(mapp[para]);
}
//sorting
model.Test= model.Test.OrderBy(paras[0]).ThenBy(paras[1]).ThenBy(paras[2]);
Thanks all,
Actually you are looking for dynamic linq query than you can try out Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
which allow to do like this
it means you can dynamically pass string propertyname to short you collection in orderby function
You can also read about : Dynamic query with Linq
You can compose the expression (any Expression) manually from pieces and then append it to the previous part of query. You can find more info, with example in "Sorting in IQueryable using string as column name".

Where clause in Linq efficiency?

The beginning of my Linq query is below.
Pay attention only to the where clause. Does Linq do the ToLower() only once? Or does it do ToLower() for every element of searchWords?
var products = from d in xElem.Descendants(fileName)
where searchWords.All(t => d.Element(productName).Value.ToLower().Contains(t))
Assuming this is LINQ to Objects, it will absolutely do it (and indeed the Element call) on each element of searchWords. There's nowhere it could really store state to do anything else, implicitly. You can optimize this easily yourself though:
var products = from d in xElem.Descendants(fileName)
let lowerD = d.Element(productName).Value.ToLower()
where searchWords.All(t => lowerD.Contains(t))
Or in a non-query expression you could use a statement lambda:
var products = xElem.Descendants(fileName)
.Where(d => {
string lowerD = d.Element(productName).Value.ToLower();
return searchWords.All(t => lowerD.Contains(t));
})
... // rest of query
Note that there are other ways of performing case-insensitive comparisons which are more robust. For example:
var products = from d in xElem.Descendants(fileName)
let v = d.Element(productName).Value
where searchWords.All(t =>
v.IndexOf(t, StringComparison.CurrentCultureIgnoreCase) != -1)

how to match string in a list

I'm having a list of string like
var target = new List<string>() { "C", "C-sharp", "java" };
I'm having a string request = "C is a programming language"
This list should match with the string and should return
C,C-sharp
How can i do this?
here is the solution with linq
var m = from t in target
where t[0] == 'C'
select t;
Using Linq and String.Contains:
var filtered = target.Where(str => str.Contains("C"));
Another option, without Linq, is to change the existing list using List<T>.RemoveAll:
target.RemoveAll(str => !str.Contains("C"));
If you really need a regex (for something more complex), you may also use:
Regex validate = new Regex(".a.", RegexOptions.IgnoreCase);
var filtered = target.Where(str => validate.Match(str).Success);

Resources