How to search for any text in List<String> - c#

I have list and I need to search for items something like:
if the user searches for smi it will bring all items that include smi?
Any idea?

Check the following example
string serachKeyword ="o";
List<string> states = new List<string>();
states.Add("Frederick");
states.Add("Germantown");
states.Add("Arlington");
states.Add("Burbank");
states.Add("Newton");
states.Add("Watertown");
states.Add("Pasadena");
states.Add("Maryland");
states.Add("Virginia");
states.Add("California");
states.Add("Nevada");
states.Add("Ohio");
List<string> searchResults = states.FindAll(s => s.Contains(serachKeyword));

This will find all results that start with 'smi' (mySearchString)
foreach(var result in myList.Where(s => s.IndexOf(mySearchString) == 0))
{
// Do whatever
}
This will find any that contains 'smi' (mySearchString)
foreach(var result in myList.Where(s => s.IndexOf(mySearchString,StringComparison.InvariantCultureIgnoreCase) != -1))
{
// Do whatever
}
This will search for your text (ignoring case), and return any strings that contain the text.
that should work - Don't have IDE close by, but hope it helps

To search items that Include 'smi'
var result = list.Where(s => s.Contains("smi"));

If you want to grab all of the items that contain "smi" anywhere, like "smith" and "vesmit":
var list = myList.Where(m => m.Contains("smi"));
If you want to grab all of the items that contain "smi" at the start of the string, like "smith", "smitten", and "smile":
var list = myList.Where(m => m.BeginsWith("smi"));
If you want more flexibility, you can use a Regex
var list = myList.Where(m => Regex.IsMatch(m, "regexPattern"));

If you use a version of C# without LINQ you can use the Find method of the List as described here (it's got quite big sample on that page too).

Related

Filtering a List using a separate List of values

I have a List of Vehicles with various fields such as registration, age, engine size, etc. One of these fields is a "tag" field which in itself is a List of tags.
I am trying to filter this list of vehicles to only show the ones which include a tag which matches a value in a separate neededTags list.
I am trying to do this using Linq and Lambda expressions.
I have managed to get this working in situations where the Tag field in the main List is just a normal string field, NOT a list of strings. The code for this is here:
filteredVehicles = Vehicles.Where(x => neededTags.Any(y => y == x.tags)).ToList();
where neededTags is my list of tags that I am interested in.
My problem now is that if the Tag element in the vehicles list is actually a list of tags then the compare element above says "Operator '==' cannot be applied to operands of type 'string' and 'List'"
I think I need to compare every element in the Vehicles Tag list with those in the neededTags list, but I just do not know how to do this.
Any assistance is greatly appreciated.
You want to check if the intersection of the vehicle's list of tags and the list of needed tags has any elements (if there is at least on element in vehicle's tags that is also in needed tags):
filteredVehicles = Vehicles.Where(v => v.Tags.Intersect(neededTags).Any()).ToList();
If the vehicle's tag may be null, you can use the null-conditional operator
filteredVehicles = Vehicles.Where(v => v.Tags?.Intersect(neededTags).Any() == true).ToList();
You can't compare a string to a list of strings for equality. Use the .Contains method to check for that:
// this is the short form for: .Where(x => neededTags.Any(y => x.tags.Contains(y)))
filteredVehicles = Vehicles.Where(x => neededTags.Any(x.tags.Contains)).ToList();
I think Rene V has the best answer, but this also works and I've see it done this way in other posts. You can just use the Any method on both lists. I added test data also.
filteredVehicles = Vehicles.Where(v => (v.tags ?? new List<string>()).Any(t => neededTags.Any(n => n == t))).ToList();
Test Code:
var neededTags = new List<string> { "tag1", "tag2" };
var Vehicles = new[] {
new {name = "vehicle1", tags = new List<string> { "tag1" } },
new {name = "vehicle2", tags = new List<string> { "tag5" } }
}.ToList();
var filteredVehicles = Vehicles.Where(v => (v.tags ?? new List<string>()).Any(t => neededTags.Any(n => n == t))).ToList();

Find String matches any in List of Strings

How to find string with a exact match in the list of string.
var inv_attr_string_id = inv_attr
.Where(x => ItemStringVal.Contains(x.STRING_VAL))
.Select(x => x.ID).ToList();
ItemStringVal Contains list of Strings like "0030", "1433", "2019" etc ... Now I am trying to match it with the database in such a way that if it match exactly and all the three strings then it returns me the list of IDs matched ... else it should return null.
I tried
List<int> inv_attr_string_id = new List<int>();
foreach (var StrItem in ItemStringVal)
{
inv_attr_string_id.AddRange
(
inv_attr.Where(x => x.STRING_VAL.Contains(StrItem))
.Select(x => x.ID).ToList()
);
}
I have tried .Any as well but I got an error saying "Internal .NET Framework Data Provider error 1025"
I was thinking if I could be able to write it the way it creates a query of AND condition such as it should match (Exactly) all the input strings.
One Liner could be: Select IDs if all the string matches. Else return null
If I understand the problem - You have a list of strings which is your Input Data. You also have a List of patterns that may match with Data. You want to find the pairs of [Data, Pattern]?
Upfront this can be solved in O(N^2).
Psuedo Logic be like:
Foreach item in DataCollection
Foreach pattern in PatternCollection
if(Regex.IsMatch(item, pattern)) Then collect the item & pattern in some place
Hope this gives some starting point for you to solve the problem.
You can try linq to get all those records from db which are exist int your list
var result = inv_attr.AsEnumerable().Where(x => ItemStringVal.Exists(y => y == x.STRING_VAL)).Select(x => x.Id).ToList();

How to sort numbered filenames in list in C#

I try to sort a list that contains filepaths.
And I want them to be sorted by the numbers in them.
With the given code I use I don't get the expected result.
var mylist = mylist.OrderBy(x => int.Parse(Regex.Replace(x, "[^0-9]+", "0"))).ToList<string>();
I expect the result to be:
c:\somedir\1.jpg
c:\somedir\2.jpg
c:\somedir\3.jpg
c:\somedir\7.jpg
c:\somedir\8.jpg
c:\somedir\9.jpg
c:\somedir\10.jpg
c:\somedir\12.jpg
c:\somedir\20.jpg
But the output is random.
There is a simple way of achieving that.
Let's say you have a string list like this:
List<string> allThePaths = new List<string>()
{
"c:\\somedir\\1.jpg",
"c:\\somedir\\2.jpg",
"c:\\somedir\\20.jpg",
"c:\\somedir\\7.jpg",
"c:\\somedir\\12.jpg",
"c:\\somedir\\8.jpg",
"c:\\somedir\\9.jpg",
"c:\\somedir\\3.jpg",
"c:\\somedir\\10.jpg"
};
You can get the desired result with this:
List<string> sortedPaths = allThePaths
.OrderBy(stringItem => stringItem.Length)
.ThenBy(stringItem => stringItem).ToList();
Note: Also make sure you've included LINQ:
using System.Linq;
Here is a demo example just in case it's needed.
More complex solutions can be found there.
A cleaner way of doing this would be to use System.IO.Path:
public IEnumerable<string> OrderFilesByNumberedName(IEnumerable<string> unsortedPathList) =>
unsortedPathList
.Select(path => new { name = Path.GetFileNameWithoutExtension(path), path }) // Get filename
.OrderBy(file => int.Parse(file.name)) // Sort by number
.Select(file => file.path); // Return only path

Linq intersect to filter multiple criteria against list

I'm trying to filter users by department. The filter may contain multiple departments, the users may belong to multiple departments (n:m). I'm fiddling around with LINQ, but can't find the solution. Following example code uses simplified Tuples just to make it runnable, of course there are some real user objects.
Also on CSSharpPad, so you have some runnable code: http://csharppad.com/gist/34be3e2dd121ffc161c4
string Filter = "Dep1"; //can also contain multiple filters
var users = new List<Tuple<string, string>>
{
Tuple.Create("Meyer", "Dep1"),
Tuple.Create("Jackson", "Dep2"),
Tuple.Create("Green", "Dep1;Dep2"),
Tuple.Create("Brown", "Dep1")
};
//this is the line I can't get to work like I want to
var tuplets = users.Where(u => u.Item2.Intersect(Filter).Any());
if (tuplets.Distinct().ToList().Count > 0)
{
foreach (var item in tuplets) Console.WriteLine(item.ToString());
}
else
{
Console.WriteLine("No results");
}
Right now it returns:
(Meyer, Dep1)
(Jackson, Dep2)
(Green, Dep1;Dep2)
(Brown, Dep1)
What I would want it to return is: Meyer,Green,Brown. If Filter would be set to "Dep1;Dep2" I would want to do an or-comparison and find *Meyer,Jackson,Green,Brown" (as well as distinct, as I don't want Green twice). If Filter would be set to "Dep2" I would only want to have Jackson, Green. I also played around with .Split(';'), but it got me nowhere.
Am I making sense? I have Users with single/multiple departments and want filtering for those departments. In my output I want to have all users from the specified department(s). The LINQ-magic is not so strong on me.
Since string implements IEnumerable, what you're doing right now is an Intersect on a IEnumerable<char> (i.e. you're checking each letter in the string). You need to split on ; both on Item2 and Filter and intersect those.
var tuplets = users.Where(u =>
u.Item2.Split(new []{';'})
.Intersect(Filter.Split(new []{';'}))
.Any());
string[] Filter = {"Dep1","Dep2"}; //Easier if this is an enumerable
var users = new List<Tuple<string, string>>
{
Tuple.Create("Meyer", "Dep1"),
Tuple.Create("Jackson", "Dep2"),
Tuple.Create("Green", "Dep1;Dep2"),
Tuple.Create("Brown", "Dep1")
};
//I would use Any/Split/Contains
var tuplets = users.Where(u => Filter.Any(y=> u.Item2.Split(';').Contains(y)));
if (tuplets.Distinct().ToList().Count > 0)
{
foreach (var item in tuplets) Console.WriteLine(item.ToString());
}
else
{
Console.WriteLine("No results");
}
In addition to the other answers, the Contains extension method may also be a good fit for what you're trying to do if you're matching on a value:
var result = list.Where(x => filter.Contains(x.Value));
Otherwise, the Any method will accept a delegate:
var result = list.Where(x => filter.Any(y => y.Value == x.Value));

Getting index of duplicate items in a list in c#

I am looking for a way to get the index of all elements in a list from a keyword search within the list. So for example my list has:
Hello World
Programming Rocks
Hello
Hello World
I love C#
Hello
Now from this list of strings, i want to get all the indices of elements that say Hello World. I have tried the following but it only returns the first index it finds that has my search criteria:
for (int i = 0; i< searchInList.Count; i++)
foundHelloWorld[i] = searchInList.IndexOf("Hello World");
Anyone know of a way to do this?
Thanks
searchInList.Select((value, index) => new {value, index})
.Where(a => string.Equals(a.value, "Hello World"))
.Select(a => a.index)
If you're trying to search for more than just "Hello World", you could do
searchInList.Select((value, index) => new {value, index})
.Where(a => stringsToSearchFor.Any(s => string.Equals(a.value, s)))
.Select(a => a.index)
Since you know you're looking for ALL occurrences and therefore you must traverse the entire list anyway, you'll gain a lot of readability over using IndexOf by simply examining each element yourself:
var i=0;
foreach(var value in searchInList)
{
if(value == "Hello World")
foundHelloWorld.Add(i); //foundHelloWorld must be an IList
i++;
}
You can also use an overload of the Linq Select method that incorporate's the element's index in the source collection; this should be highly readable (and thus maintainable) to Linq-experienced programmers:
foundHelloWorld = searchInList
.Select((v,i)=>new {Index = i, Value = v})
.Where(x=>x.Value == "Hello World")
.Select(x=>x.Index)
.ToList();
The above code takes the list and transforms the string into a simple anonymous type incorporating each item's place in the original list. Then, it filters down to only matching elements, and then it projects out the Index (which didn't change through the filtering) into a new List object. However, all this transformation will make this solution perform slower, because this statement will traverse the entire list multiple times.
A little ugly but will work:
var searchInList = new List<string>();
//Populate your list
string stringToLookUp= "Hello world";
var foundHelloWorldIndexes = new List<int>();
for (int i = 0; i < searchInList.Count; i++)
if (searchInList[i].Equals(stringToLookUp))
foundHelloWorldIndexes.Add(i);
The FindAll method for lists is here. The list extension method Where is here.
Both of these will do pretty much exactly what you want and they are pretty easy to use. There are abundant examples of each on the internet but if you need help using them just let me know.

Categories

Resources