How to find a string in text - linq

I'm having a list
var library = new List<string>() { "personal assistant", "sales manager", "engineer" };
and a text which is declared as
string target = "I'm a personal assistant to sales manager"";
I need to match the list with the text and should return the match count.
For the above sample i should get a count of 2 since target is having personal assistant and sales manager.

Maybe something like this:
int count = library.Count(s => target.Contains(s));
This one doesn't check for multiple occurrences of one string, though.

Related

Parameter options for User Defined Functions in PowerQuery

Hi i have been trying to make a user defined function that allows the user to select the values which the function will use from a list.
I have tried setting the parameter i want as a list to type list in my function but this only seems to accept columns rather than a list of values a user can select from.
let
ListOfDays = {1.1,0.5,2,3,1},
DayOfTheWeek = (Day as list, HoursWorked ) =>
let
Earnings = Day * HoursWorked
in
Earnings
in
DayOfTheWeek
What i would like is for me to allow the user to select a single value from the ListOfDays list. I used typed list within my function parameters so that it can give the user a dropdown list kind of option.
I believe this is the relevant documentation you are looking for:
github.com/microsoft/DataConnectors/docs/function-docs.md: Adding Function Documentation
In particular, look at the definition for Documentation.AllowedValues:
List of valid values for this parameter. Providing this field will change the input from a textbox to a drop down list. Note, this does not prevent a user from manually editing the query to supply alternate values.
This (and other Documentation fields) are part of the meta typing of the function arguments. Scroll down to the code snippet which shows how to use them:
[DataSource.Kind="HelloWorldWithDocs", Publish="HelloWorldWithDocs.Publish"]
shared HelloWorldWithDocs.Contents = Value.ReplaceType(HelloWorldImpl, HelloWorldType);
HelloWorldType = type function (
message as (type text meta [
Documentation.FieldCaption = "Message",
Documentation.FieldDescription = "Text to display",
Documentation.SampleValues = {"Hello world", "Hola mundo"}
]),
optional count as (type number meta [
Documentation.FieldCaption = "Count",
Documentation.FieldDescription = "Number of times to repeat the message",
Documentation.AllowedValues = { 1, 2, 3 }
]))
as table meta [
Documentation.Name = "Hello - Name",
Documentation.LongDescription = "Hello - Long Description",
Documentation.Examples = {[
Description = "Returns a table with 'Hello world' repeated 2 times",
Code = "HelloWorldWithDocs.Contents(""Hello world"", 2)",
Result = "#table({""Column1""}, {{""Hello world""}, {""Hello world""}})"
],[
Description = "Another example, new message, new count!",
Code = "HelloWorldWithDocs.Contents(""Goodbye"", 1)",
Result = "#table({""Column1""}, {{""Goodbye""}})"
]}
];
HelloWorldImpl = (message as text, optional count as number) as table =>
let
_count = if (count <> null) then count else 5,
listOfMessages = List.Repeat({message}, _count),
table = Table.FromList(listOfMessages, Splitter.SplitByNothing())
in
table;
They also provide a screenshot of what this should look like when invoked:
If the user is able to open up the Query Editor, then they can choose a Day parameter from a dropdown list and have this automatically apply to the query.
You would create the parameter from the Manage Parameters > New Parameter menu
The drop-down at the upper right of the image is how the user would select the choice.
Your User Defined Function fn_DayOfTheWeek would be the following:
let
DayOfTheWeek = (Day as number, HoursWorked as number) =>
let
Earnings = Day * HoursWorked
in
Earnings
in
DayOfTheWeek
Note that Day is a number, not a list. You want to choose from a list, not pass a list into the function.
Now you can invoke your function with your parameter to actually produce a result.
let
Source = fn_DayOfTheWeek(Day, <HoursWorked value here>)
in
Source
This result will update when you change the parameter.
As you can see, whether a user has access to the Query Editor is rather a critical question for this approach. I'm not sure if it's possible to somehow set a parameter directly within a custom connector dialog box or not but this should be equivalent in functionality.

How to search with dynamic entity names with linq

Basically all I'm looking to do is something like the following:
string EntityFrameworkType = "Product";
string searchField = "ProductName";
string searchValue = "My Product";
using( var context = new entitycontext())
{
var result = (from x in context.EntityFrameworkType.Where(l=>l.searchField == searchValue) select x).FirstOrDefault();
}
of course this syntax won't work because context does not contain an entity called "EntityFrameworkType"...
Is it possible to do this another way??? What I'm looking to do in generalize my database duplicate check. In this example, I'm searching for any Product with the Name "My Product". But I'd like to be able to pass in these string for say, ProductCategory with ProductCategoryId = 1.... etc...
you can have a look here to get the idea of how it is done.
You'll need to learn about Expression

LINQ Lamba Select all from table where field contains all elements in list

I need a Linq statement that will select all from a table where a field contains all elements in a list<String> while searching other fields for the entire string regardless of words.
It's basically just a inclusive word search on a field where all words need to be in the record and string search on other fields.
Ie I have a lookup screen that allows the user to search AccountID or Detail for the entire search string, or search clientID for words inclusive words, I'll expand this to the detail field if I can figure out the ClientId component.
The complexity is that the AccountId and Detail are being searched as well which Basically stops me from doing the foreach in the second example due to the "ors".
Example 1, this gives me an the following error when I do query.Count() afterwards:
query.Count(); 'query.Count()' threw an exception of type 'System.NotSupportedException' int {System.NotSupportedException}
+base {"Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator."} System.SystemException {System.NotSupportedException}
var StrList = searchStr.Split(' ').ToList();
query = query.Where(p => p.AccountID.Contains(searchStr) || StrList.All(x => p.clientID.Contains(x)) || p.Detail.Contains(searchStr));
Example 2, this gives me an any search word type result:
var StrList = searchStr.Split(' ').ToList();
foreach (var item in StrList)
query = query.Where(p => p.AccountID.Contains(searchStr) || p.clientID.Contains(item) || p.Detail.Contains(searchStr));
Update
I have a table with 3 fields, AccountID, ClientId, Details
Records
Id, AccountID, CLientId, Details
1, "123223", "bobo and co", "this client suxs"
2, "654355", "Jesses hair", "we like this client and stuff"
3, "456455", "Microsoft", "We love Mircosoft"
Search examples
searchStr = "232"
Returns Record 1;
searchStr = "bobo hair"
Returns no records
searchStr = "bobo and"
Returns Record 1
searchStr = "123 bobo and"
Returns returns nothing
The idea here is:
if the client enters a partial AccountId it returns stuff,
if the client wants to search for a ClientId they can type and cancel down clients by search terms, ie word list. due to the large number of clients the ClientID Will need to contain all words (in any order)
I know this seems strange but it's just a simple interface to find accounts in a powerful way.
I think there are 2 solutions to your problem.
One is to count the results in memory like this:
int count = query.ToList().Count();
The other one is to not use All in your query:
var query2 = query;
foreach (var item in StrList)
{
query2 = query2.Where(p => p.clientID.Contains(item));
}
var result = query2.Union(query.Where(p => p.AccountID.Contains(searchStr) || p.Detail.Contains(searchStr)));
The Union at the end acts like an OR between the 2 queries.

linq query how to take out spaces in strings

I am trying to match a string typed in by a user to a string in a database.
Before I try match them i need to take the spaces out both of them.
how do i do this?
public static Product GetProductbypart(ModelContainer context, string partnumber)
{
var query = from product in context.Products
where product.Partnumber == partnumber
select product;
return query.FirstOrDefault();
}
this is my query which works if the user types in the exact part number. But some users may type it in with too many spaces or too less.
I want to take the partnumber take out the spaces. Then take the product.Partnumber and take of the spaces of that also, to see if there is a match.
Sample inputs:
MC-9a 1a AC24V
MC-9a 50/60Hz
1
123
MC+123-1
F6h67e
_8jj+j7s
string partnumber = partnumber.Replace(" ", String.Emtpy);
var query = from product in context.Products
where product.Partnumber.Replace("", String.Empty) == partnumber
select product;
This removes spaces in the strings product.Partnumber and partnumber. However, if you use linq-to-SQL the part product.Partnumber.Replace(..) won't work. But I'm not sure why you have to remove spaces of the product number in the database. Sounds like inconsistent data to me.
public static Product GetProductbypart(ModelContainer context, string partnumber)
{
partnumber = partnumber.Replace(" ", String.Empty);
var products = from product in context.Products
select product;
foreach(var item in products)
{
if (item.Partnumber != null)
{
item.Partnumber = item.Partnumber.Replace(" ", String.Empty);
if (item.Partnumber == partnumber)
{
var query = from product in context.Products
where product.Id == item.Id
select product;
return query.FirstOrDefault();
}
}
}
return null;
}
This is how i did it
In this case I would think about implementing it a little bit differently. If you need your table only in order to compare it with the user input, you can remove spaces in the database in advance, before running the query. Also there is no point in removing spaces in database, you can do it in client code.
In this case you will be able to use regular Equals and also it should be a little bit more efficient.
I think the best answer here is to not try and figure out how the user entered the data, instead make sure that they entered a valid part number in the first place. Can you provide some form of input format? Even if it means using hyphens where spaces are, you can always remove them before you check, but at least you'll have data in the correct format.

At least one one object must implement Icomparable

I am attempting to get unique values in a list of similar value distinguished only by a one element in a pipe delimited string... I keep getting at least one object must implement Icomparable. I don't understand why I keep getting that. I am able to groupBy that value... Why can't I find the max... I guess it is looking for something to compare it with. If I get the integer version will it stop yelling at me? This is the last time I am going to try using LINQ...
var queryResults = PatientList.GroupBy(x => x.Value.Split('|')[1]).Select(x => x.Max());
I know I can get the unique values some other way. I am just having a hard time figuring it out. In that List I know that the string with the highest value amongst its similar brethren is the one that I want to add to the list. How can I do that? I am totally drawing a blank because I have been trying to get this to work in linq for the last few days with no luck...
foreach (XmlNode node in nodeList)
{
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(node.OuterXml);
string popPatInfo = xDoc.SelectSingleNode("./template/elements/element[#name=\"FirstName\"]").Attributes["value"].Value + ", " + xDoc.SelectSingleNode("./template/elements/element[#name=\"LastName\"]").Attributes["value"].Value + " | " + DateTime.Parse(xDoc.SelectSingleNode("./template/elements/element[#name=\"DateOfBirth\"]").Attributes["value"].Value.Split('T')[0]).ToString("dd-MMM-yyyy");
string patientInfo = xDoc.SelectSingleNode("./template/elements/element[#name=\"PatientId\"]").Attributes["value"].Value + "|" + xDoc.SelectSingleNode("./template/elements/element[#name=\"PopulationPatientID\"]").Attributes["enc"].Value;// +"|" + xDoc.SelectSingleNode("./template/elements/element[#name=\"AdminDate\"]").Attributes["value"].Value;
int enc = Int32.Parse(patientInfo.Split('|')[1]);
if (enc > temp)
{
lastEncounter.Add(enc, patientInfo);
temp = enc;
}
//lastEncounter.Add(Int32.Parse(patientInfo.Split('|')[1]));
PatientList.Add( new SelectListItem { Text = popPatInfo, Value = patientInfo });
}
I was thinking about using some kind of temp variable to find out what is the highest value and then add that string to the List. I am totally drawing a blank however...
Here I get the IDs in an anonymous type to make it readable.
var patientEncounters= from patient in PatientList
let PatientID=Int32.Parse(patient.Value.Split('|')[0])
let EncounterID=Int32.Parse(patient.Value.Split('|')[1])
select new { PatientID, EncounterID };
Then we group by UserID and get the last encounter
var lastEncounterForEachUser=from pe in patientEncounters
group pe by pe.PatientID into grouped
select new
{
PatientID=grouped.Key,
LastEncounterID=grouped.Max(g=>g.EncounterID)
};
Linq doesn't know how to compare 2 Patient objects, so it can't determine which one is the "greatest". You need to make the Patient class implement IComparable<Patient>, to define how Patient objects are compared.
// Compare objets by Id value
public int CompareTo(Patient other)
{
return this.Id.CompareTo(other.Id);
}
Another option is to use the MaxBy extension method available in Jon Skeet's MoreLinq project:
var queryResults = PatientList.GroupBy(x => x.Value.Split('|')[1])
.Select(x => x.MaxBy(p => p.Id));
EDIT: I assumed there was a Patient class, but reading your code again, I realize it's not the case. PatientList is actually a collection of SelectListItem, so you need to implement IComparable in that class.

Resources