SQL Like search in LIST and LINQ in C# - c#

I have a List which contains the list of words that needs to be excluded.
My approach is to have a List which contains these words and use Linq to search.
List<string> lstExcludeLibs = new List<string>() { "CONFIG", "BOARDSUPPORTPACKAGE", "COMMONINTERFACE", ".H", };
string strSearch = "BoardSupportPackageSamsung";
bool has = lstExcludeLibs.Any(cus => lstExcludeLibs.Contains(strSearch.ToUpper()));
I want to find out part of the string strSearch is present in the lstExcludedLibs.
It turns out that .any looks only for exact match. Is there any possibilities of using like or wildcard search
Is this possible in linq?
I could have achieved it using a foreach and contains but I wanted to use LINQ to make it simpler.
Edit: I tried List.Contains but it also doesn't seem to work

You've got it the wrong way round, it should be:-
List<string> lstExcludeLibs = new List<string>() { "CONFIG", "BOARDSUPPORTPACKAGE", "COMMONINTERFACE", ".H", };
string strSearch = "BoardSupportPackageSamsung";
bool has = lstExcludeLibs.Any(cus => strSearch.ToUpper().Contains(cus));
Btw - this is just an observation but, IMHO, your variable name prefixes 'lst' and 'str' should be ommitted. This is a mis-interpretation of Hungarian notation and is redundant.

I think the line should be:
bool has = lstExcludeLibs.Any(cus => cus.Contains(strSearch.ToUpper()));

Is this useful to you ?
bool has = lstExcludeLibs.Any(cus => strSearch.ToUpper().Contains(cus));
OR
bool has = lstExcludeLibs.Where(cus => strSearch.ToUpper().IndexOf(cus) > -1).Count() > 0;
OR
bool has = lstExcludeLibs.Count(cus => strSearch.ToUpper().IndexOf(cus) > -1) > 0;

Related

How to remove duplicates from the list in C#

Please help me to fix this issue. My dropdown list looks something like this mentioned below.
Client
Contractor,Contractor,Contractor,Manager
Contractor,Manager
Manager
Operator
Viewer
I want to remove the duplicates and my output should be like :
Client
Contractor
Manager
Operator
Viewer
This is my code mentioned below:
Property:
public List<string> TeamRoleNames => TeamRoleUids.Select(MainRoles.GetRoleName).ToList();
Display Method:
{
result += " ; TeamRoleNames=" + this.TeamRoleNames;
}
GetRole Method:
{
string roleName;
if (RoleNameByUid.TryGetValue(roleUid, out roleName))
{
return roleName;
}
return null;
}
I have tried with Distinct Method mentioned below, But did not work like the output what I wanted!
public List<string> TeamRoleNames => TeamRoleUids.Select(MainRoles.GetRoleName).Distinct().ToList();
How can I fix this? Can anyone help?
Having elements comma separated require you to split them first to have an homogenous collection then do the distinct
// get the comma separated values out as 1 value each
// for that you can use split, remove empty and select many
// which will return as a single level list (flat)
var result = TeamRoleUids.SelectMany(o => o.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)).Distinct().ToList();
Consider converting the list to a set (hashset) since sets as a data structure doesn't allow duplicates.
More about hashsets form official documentation.
So, the solution would be similar to the following:
var hashSet = new HashSet<YourType>(yourList);
example:
var hashSet = new HashSet<string>(TeamRoleUids);
then converting it back toList() will remove duplicates.
If you have already tried Distinct and it hasn't worked, then you could do the following;
Split your string list to a List<string>
List<string> result = TeamRoleNames.Split(',').ToList();
Then when you're adding them to the dropdwon, check to see if the role is already in the dropdown. If so, move on, else add to the dropdown.
So something like
foreach(var role in this.TeamRoleNames)
{
if(!result.contains(role))
result += " ; TeamRoleNames=" + role;
}
You can use SelectMany to flatten a enumeration containing a nested enumeration. Here, we create the nested enumeration by splitting the string at the commas:
string[] input = {
"Client",
"Contractor,Contractor,Contractor,Manager",
"Contractor,Manager",
"Manager",
"Operator",
"Viewer"
};
var roles = input
.SelectMany(r => r.Split(','))
.Distinct()
.OrderBy(r => r)
.ToList();
foreach (string role in roles) {
Console.WriteLine(role);
}
prints
Client
Contractor
Manager
Operator
Viewer

C# Return match found with Contains

I need to return all matches found when comparing a block of text with a list of strings.
if(myList.Any(myText.Contains))
I can verify that there is a match with the above, but I'm not sure how to go further and return the matching string. I looked into Intersect, but as far as I understood it only works on two of the same type.
Sample data:
myList[] = { "City of London", "City of Edinburgh" }; etc
myText = "I am applying for the position in the City of London";
The desired result here would be "City of London", either via setting the resulting match as a string, or returning the index of myList. Any help greatly appreciated, thanks!
This should work.
List<string> myList = new List<string>();
myList.Add("City of London");
myList.Add("City of Edinburgh");
string myText = "I am applying for the position in the City of London";
var result = myList.Where(x => myText.Contains(x)).ToList();
try this:
string result= myList.FindAll(x=> myText.IndexOf(x)>-1);
var matches = myList.Where(a => myText.IndexOf(a) > 0).ToList();

C#: LINQ query with split and parsing

I have an object with a String field containing a comma separated list of integers in it. I'm trying to use LINQ to retrieve the ones that have a specific number in the list.
Here's my approach
from p in source
where (p.Keywords.Split(',').something.Contains(val))
select p;
Where p.Keywords is the field to split.
I've seen the following in the net but just doesn't compile:
from p in source
where (p.Keywords.Split(',').Select(x=>x.Trim()).Contains(val))
select p;
I'm a LINQ newbie, but had success with simpler queries.
Update:
Looks like I was missing some details:
source is a List containing the object with the field Keywords with strings like 1,2,4,7
Error I get is about x not being defined.
Here's an example of selecting numbers that are greater than 3:
string str = "1,2,3,4,5,6,7,8";
var numbers = str.Split(',').Select(int.Parse).Where(num => num > 3); // 4,5,6,7,8
If you have a list then change the Where clause:
string str = "1,2,3,4,5,6,7,8";
List<int> relevantNums = new List<int>{5,6,7};
var numbers = str.Split(',').Select(int.Parse).Where(num => relevantNums.Contains(num)); // 5,6,7
If you are not looking for number but for strings then:
string str = "1,2,3,4,5,6,7,8";
List<string> relevantNumsStr = new List<string>{"5","6","7"};
var numbers = str.Split(',').Where(numStr => relevantNumsStr.Contains(numStr)); // 5,6,7
Here is an example of how you can achieve this. For simplicity I did to string on the number to check for, but you get the point.
// class to mimic what you structure
public class MyObj
{
public string MyStr{get;set;}
}
//method
void Method()
{
var myObj = new List <MyObj>
{
new MyObj{ MyStr="1,2,3,4,5"},
new MyObj{ MyStr="9,2,3,4,5"}
};
var num =9;
var searchResults = from obj in myObj
where !string.IsNullOrEmpty(obj.MyStr) &&
obj.MyStr.Split(new []{','})
.Contains(num.ToString())
select obj;
foreach(var item in searchResults)
Console.WriteLine(item.MyStr);
}
Thanks for all the answers, although not in the right language they led me to the answer:
from p in source where (p.Keywords.Split(',').Contains(val.ToString())) select p;
Where val is the number I'm looking for.

Comparing two strings with different orders

I have a dictionary with a list of strings that each look something like:
"beginning|middle|middle2|end"
Now what I wanted was to do this:
List<string> stringsWithPipes = new List<string>();
stringWithPipes.Add("beginning|middle|middle2|end");
...
if(stringWithPipes.Contains("beginning|middle|middle2|end")
{
return true;
}
problem is, the string i'm comparing it against is built slightly different so it ends up being more like:
if(stringWithPipes.Contains(beginning|middle2|middle||end)
{
return true;
}
and obviously this ends up being false. However, I want to consider it true, since its only the order that is different.
What can I do?
You can split your string on | and then split the string to be compared, and then use Enumerable.Except along with Enumerable.Any like
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
stringsWithPipes.Add("beginning|middle|middle3|end");
stringsWithPipes.Add("beginning|middle2|middle|end");
var array = stringsWithPipes.Select(r => r.Split('|')).ToArray();
string str = "beginning|middle2|middle|end";
var compareArray = str.Split('|');
foreach (var subArray in array)
{
if (!subArray.Except(compareArray).Any())
{
//Exists
Console.WriteLine("Item exists");
break;
}
}
This can surely be optimized, but the above is one way to do it.
Try this instead::
if(stringWithPipes.Any(P => P.split('|')
.All(K => "beginning|middle2|middle|end".split('|')
.contains(K)))
Hope this will help !!
You need to split on a delimeter:
var searchString = "beginning|middle|middle2|end";
var searchList = searchString.Split('|');
var stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
...
return stringsWithPipes.Select(x => x.Split('|')).Any(x => Match(searchList,x));
Then you can implement match in multiple ways
First up must contain all the search phrases but could include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x));
}
Or must be all the search phrases cannot include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x)) && search.Length == match.Length;
}
That should work.
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
string[] stringToVerifyWith = "beginning|middle2|middle||end".Split(new[] { '|' },
StringSplitOptions.RemoveEmptyEntries);
if (stringsWithPipes.Any(s => !s.Split('|').Except(stringToVerifyWith).Any()))
{
return true;
}
The Split will remove any empty entries created by the doubles |. You then check what's left if you remove every common element with the Except method. If there's nothing left (the ! [...] .Any(), .Count() == 0 would be valid too), they both contain the same elements.

Searching a list of strings in C#

So I want to use one of these LINQ functions with this List<string> I have.
Here's the setup:
List<string> all = FillList();
string temp = "something";
string found;
int index;
I want to find the string in all that matches temp when both are lower cased with ToLower(). Then I'll use the found string to find it's index and remove it from the list.
How can I do this with LINQ?
I get the feeling that you don't care so much about comparing the lowercase versions as you do about just performing a case-insensitive match. If so:
var listEntry = all.Where(entry =>
string.Equals(entry, temp, StringComparison.CurrentCultureIgnoreCase))
.FirstOrDefault();
if (listEntry != null) all.Remove(listEntry);
OK, I see my imperative solution is not getting any love, so here is a LINQ solution that is probably less efficient, but still avoids searching through the list two times (which is a problem in the accepted answer):
var all = new List<string>(new [] { "aaa", "BBB", "Something", "ccc" });
const string temp = "something";
var found = all
.Select((element, index) => new {element, index})
.FirstOrDefault(pair => StringComparer.InvariantCultureIgnoreCase.Equals(temp, pair.element));
if (found != null)
all.RemoveAt(found.index);
You could also do this (which is probably more performant than the above, since it does not create new object for each element):
var index = all
.TakeWhile(element => !StringComparer.InvariantCultureIgnoreCase.Equals(temp, element))
.Count();
if (index < all.Count)
all.RemoveAt(index);
I want to add to previous answers... why don't you just do it like this :
string temp = "something";
List<string> all = FillList().Where(x => x.ToLower() != temp.ToLower());
Then you have the list without those items in the first place.
all.Remove(all.FirstOrDefault(
s => s.Equals(temp,StringComparison.InvariantCultureIgnoreCase)));
Use the tool best suited for the job. In this case a simple piece of procedural code seems more appropriate than LINQ:
var all = new List<string>(new [] { "aaa", "BBB", "Something", "ccc" });
const string temp = "something";
var cmp = StringComparer.InvariantCultureIgnoreCase; // Or another comparer of you choosing.
for (int index = 0; index < all.Count; ++index) {
string found = all[index];
if (cmp.Equals(temp, found)) {
all.RemoveAt(index);
// Do whatever is it you want to do with 'found'.
break;
}
}
This is probably as fast as you can get, because:
Comparison it done in place - there is no creation of temporary uppercase (or lowercase) strings just for comparison purposes.
Element is searched only once (O(index)).
Element is removed in place without constructing a new list (O(all.Count-index)).
No delegates are used.
Straight for tends to be faster than foreach.
It can also be adapted fairly easily should you want to handle duplicates.

Categories

Resources