List.Any get matched String - c#

FilePrefixList.Any(s => FileName.StartsWith(s))
Can I get s value here? I want to display the matched string.

Any determines only if there is a match, it doesn't return anything apart from the bool and it needs to execute the query.
You can use Where or First/FirstOrDefault:
string firstMastch = FilePrefixList.FirstOrDefault(s => FileName.StartsWith(s)); // null if no match
var allMatches = FilePrefixList.Where(s => FileName.StartsWith(s));
string firstMastch = allMatches.FirstOrDefault(); // null if no match
So Any is fine if all you need to know is if ther's a match, otherwise you can use FirstOrDefault to get the first match or null(in case of reference types).
Since Any needs to execute the query this is less efficient:
string firstMatch = null;
if(FilePrefixList.Any(s => FileName.StartsWith(s)))
{
// second execution
firstMatch = FilePrefixList.First(s => FileName.StartsWith(s));
}
If you want to put all matches into a separate collection like a List<string>:
List<string> matchList = allMatches.ToList(); // or ToArray()
If you want to output all matches you can use String.Join:
string matchingFiles = String.Join(",", allMatches);

Not with Any, no... that's only meant to determine whether there are any matches, which is why it returns bool. However, you can use FirstOrDefault with a predicate instead:
var match = FilePrefixList.FirstOrDefault(s => FileName.StartsWith(s));
if (match != null)
{
// Display the match
}
else
{
// Nothing matched
}
If you want to find all the matches, use Where instead.

if FilePrefixList is a List<string>, you can use List<T>.Find method:
string first = FilePrefixList.Find(s => FileName.StartsWith(s));
fiddle: List.Find vs LINQ (Find is faster)
List<T>.Find (MSDN) returns the first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type T

Enumerable.Any() returns bool denoting whether any item matched the criteria.
If you need the matched item, use SingleOrDefault() instead:
var matchedPrefix = FilePrefixList.SingleOrDefault(s => FileName.StartsWith(s));
See MSDN

please check try this:
we assuming FilePrefixList is collectionlist
class A
{
public int ID { get; set; }
public string Name { get; set; }
}
List<A> FilePrefixList= new List<A>();
FilePrefixList.Add(new A
{
ID = 1,
Name = "One"
});
FilePrefixList.Add(new A
{
ID =2,
Name = "Two"
});
FilePrefixList.Add(new A
{
ID = 3,
Name = "Three"
});
select data from list is:
var listItems = FilePrefixList.Where(x =>x.Name.StartsWith("T")).ToList();

Related

Filter a collection column by multiple values

I have a collection and I would like to filter it with one of the column contains multiple values. The filter values are dynamically generated and I dont know how many I will get.
I tried the following without success:
var input = #"was.Name.Contains(""Test"") || was.Name.Contains(""Test2"")";
var test = collection.Where(was => input)).ToList();
Assuming you receive the filter values as a CSV string:
var csvFilters = "Test1, Test2";
// split by ',', remove empty entries,
// trim each filter and store the result in a list
var filters = csvFilters.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToList();
// return items in collection whose Name property
// is equal to any of the items in filters
var result = collection.Where(x => filters.Contains(x.Name)).ToList();
This should translate to the following SQL:
SELECT * FROM collection c
WHERE c.Name IN ('Test1', 'Test2')
I guess you want to use LINQ. The question is, how the "filter" values are kept? I'll answer in the way I understand your question.
If input is supposed to be a condition then I'd suggest using Func<Object,bool>. This means, the input would be the condition you're looking for, and if found, it would return true.
Here is a simple example:
IEnumerable <T> FindElements (Func<Object, bool> condition, IEnumerable<T> inputList)
{
List<T> outputList = new List<T>();
foreach(var element in inputList)
{
if(condition != null && condition(element))
outputList.Add(element);
}
return outputList;
}
Then, if you call the function given exemplary parameters:
string input[] = {"Test1","Test2"};
foreach(string s in input)
{
targetList = FindElements(element=>((cast)element).Name.Contains(s), collection);
}
You should get all elements in collection which name has Test1 or Test2. Cast is of course name of the class which element instantiates.

find the longest match of a string in list c#

I have a list of string I need to find the longest match of my search string in the list.
for example the list contains : "test", "abc", "testing", "testingap" and my search string is 'testingapplication'
the result should be 'testingap'
here is what I did so far , it does the work but I'm looking is there any better efficient way to do this
string search= "testingapplication";
List<string> names = new List<string>(new[] { "test", "abc", "testing", "testingap" });
List<string> matchedItems = new List<string>();
foreach (string item in names)
{
if (search.Contains(item))
{
matchedItems.Add(item);
Console.WriteLine(item);
}
}
var WordMatch= matchedItems.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
Console.WriteLine("WordMatch"+WordMatch);
Since you are already using LINQ, you could consider ordering your "names" by length via the OrderByDescending() method and grab the first that contains your string using FirstOrDefault() as seen below:
var match = names.OrderByDescending(n => n.Length)
.FirstOrDefault(n => search.Contains(n));
if (match == null)
{
// No match was found, handle accordingly.
}
else
{
// match will contain your longest string
}

Sort List based on Array

I am trying to sort a custom list based on a string array, but I am failing miserably e.g. its not sorting the list at all,
Public class CrateOrder
{
public int Id { get; set; }
public string Name { get; set; }
public Stream OrderStream { get; set; }
}
string[] selectedFruits = {"Apple", "Mango"}; // in real get from web services
var selectedFruitsList = selectedFruits.ToList();
List<CrateOrder> cFruit = GetCrateOrderFromWebServices();
var sorted = cFruit.OrderBy(s => selectedFruitsList.IndexOf(s.Name)).ToList();
It's not sorting the list properly, I want CrateOrder list item to be ordered based on selectedFruits...
If the Name property of your fruit does not match your ordering list exactly, IndexOf will always return -1. To get around this specify a case-insensitive StringComparison, but that is not available as an overload to IndexOf so you have to use a slightly more complex method:
var sorted = cFruit.OrderBy(
s => selectedFruitsList.FindIndex(
x => x.Equals(s.Name, StringComparison.OrdinalIgnoreCase)) )
.ToList();
You are almost there. The code orders the fruit from selectedFruitsList after all other items, because OrderBy order is ascending, and they are the only ones for which a non-negative number is returned.
To fix this, reverse selectedFruits, and negate the result of IndexOf, like this:
string[] selectedFruits = {"Mango", "Apple"};
...
var sorted = cFruit.OrderBy(s => -selectedFruitsList.IndexOf(s.Name)).ToList();
Alternatively, you could expand the code to deal with negative indexes explicitly:
string[] selectedFruits = {"Apple", "Mango"};
...
var sorted = cFruit.OrderBy(s => {
int index = selectedFruitsList.IndexOf(s.Name);
return index < 0 ? int.MaxValue : index;
}).ToList();
I wasn't aware if its case sensitive, can i add ignore culture to it
No - Array.IndexOf does not have parameters that let you customize the equality comparison.
Just change all of your selectedfruits and the search value to lower case:
string[] selectedFruits = {"Apple", "Mango"}; // in real get from web services
var selectedFruitsList = selectedFruits.Select(s => s.ToUpperInvariant()).ToList();
List<CrateOrder> cFruit = GetCrateOrderFromWebServices();
var sorted = cFruit.OrderBy(s => selectedFruitsList.IndexOf(s.Name.ToUpperInvariant())).ToList;

search the database for the words within a string

Imagine that a user entered a sentence and I need to search for the subjects that consist of words within the entered sentence. These are the code that I thought they could solve the case.
var result = from x in dataBase.tableName
select x;
string[] words = enteredString.Split();
foreach(string word in words)
{
result = result.Where(x => x.subject.Contains(word));
}
it shows only the search result with the last word in sentence, but I thought the result must be narrowed down each time a word is used in the where line.
Try this:
foreach(string word in words)
{
var temp = word;
result = result.Where(x => x.subject.Contains(temp));
}
This is called (by ReSharper at least) "access to modified closure" - lambda expressions don't capture the value, they capture the entire variable. And the value of the variable word is changing with each iteration of the loop. So, since the Where() method is lazy-evaluated, by the time this sequence is consumed, the value of word is the last one in the sequence.
I hade some success by inverting the logic like this:
string[] words = enteredString.Split();
var results = from x in database.TableName
where words.Any(w => x.subject.Contains(w))
select x;
-- Edit
A more generic approach, for this kind of queries, would be:
class SearchQuery
{
public ICollection<string> Include { get; private set; }
public ICollection<string> Exclude { get; private set; }
}
[...]
SearchQuery query = new SearchQuery
{
Include = { "Foo" }, Exclude = { "Bar" }
}
var results = from x in database.Table
where query.Include.All(i => x.Subject.Contains(i)) &&
query.Exclude.All(i => !x.Subject.Contains(i))
select x;
This assumes that all words in query.Include must occur in Subject, if you want to find any subjects that have at least one of the words query.Include.All should be query.Include.Any
I've tested this with Entity Framework 4. Which will create a SQL query that applies all criteria in the database rather than in memory.
Here you go:
var result = from x in dataBase.tableName
select x;
string[] words = enteredString.Split();
result.Where(r => words.Any(w => r.Subject.Contains(w));
it can't do the thing - since with every word you are overwriting the previous result - you need to do something similar to:
List<object> AllResults = new List<object>();
foreach(string word in words)
{
var temp = word;
AllResults.AddRange (result.Where(x => x.subject.Contains(temp)).ToList());
}
Not sure what type your result type is hence the List<object>...

Select single item from a list

Using LINQ what is the best way to select a single item from a list if the item may not exists in the list?
I have come up with two solutions, neither of which I like. I use a where clause to select the list of items (which I know will only be one), I can then check the count and make a Single call on this list if count is one, the other choice is to use a foreach and just break after getting the item.
Neither of these seem like a good approach, is there a better way?
You can use IEnumerable.First() or IEnumerable.FirstOrDefault().
The difference is that First() will throw if no element is found (or if no element matches the conditions, if you use the conditions). FirstOrDefault() will return default(T) (null if it's a reference type).
Use the FirstOrDefault selector.
var list = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var firstEven = list.FirstOrDefault(n => n % 2 == 0);
if (firstEven == 0)
Console.WriteLine("no even number");
else
Console.WriteLine("first even number is {0}", firstEven);
Just pass in a predicate to the First or FirstOrDefault method and it'll happily go round' the list and picks the first match for you.
If there isn't a match, FirstOrDefault will returns the default value of whatever datatype the list items is.
Hope this helps :-)
List<string> items = new List<string>();
items.Find(p => p == "blah");
or
items.Find(p => p.Contains("b"));
but this allows you to define what you are looking for via a match predicate...
I guess if you are talking linqToSql then:
example looking for Account...
DataContext dc = new DataContext();
Account item = dc.Accounts.FirstOrDefault(p => p.id == 5);
If you need to make sure that there is only 1 item (throws exception when more than 1)
DataContext dc = new DataContext();
Account item = dc.Accounts.SingleOrDefault(p => p.id == 5);
Just to complete the answer, If you are using the LINQ syntax, you can just wrap it since it returns an IEnumerable:
(from int x in intList
where x > 5
select x * 2).FirstOrDefault()
Maybe I'm missing something here, but usually calling .SingleOrDefault() is the way to go to return either the single element in the list, or a default value (null for reference or nullable types) if the list is empty.
It generates an exception if the list contains more than one element.
Use FirstOrDefault() to cover the case where you could have more than one.
There are two easy ways, depending on if you want to deal with exceptions or get a default value.
You can use the First<T>() or the FirstOrDefault<T>() extension method to get the first result or default(T).
var list = new List<int> { 1, 2, 4 };
var result = list.Where(i => i == 3).First(); // throws InvalidOperationException
var result = list.Where(i => i == 3).FirstOrDefault(); // = 0
SingleOrDefault() is what you need
cheers
just saw this now, if you are working with a list of object you can try this
public class user
{
public string username { get; set; }
public string password { get; set; }
}
List<user> userlist = new List<user>();
userlist.Add(new user { username = "macbruno", password = "1234" });
userlist.Add(new user { username = "james", password = "5678" });
string myusername = "james";
string mypassword = "23432";
user theUser = userlist.Find(
delegate (user thisuser)
{
return thisuser.username== myusername && thisuser.password == mypassword;
}
);
if (theUser != null)
{
Dosomething();
}
else
{
DoSomethingElse();
}

Categories