2

I am having a SeachBar in Xamarin Forms, and ListView that shows suggestions from existing list of cities. I want to get list of items matching search keyword irrespective of it being uppercase or lowercase.

For that I am having a List. I want to Search items from that list and get List of items that matched the search keyword ignoring the case. I am having a code for getting list of items that matched keyword. I just want it to include items that match search keyword ignoring the case of letters.

(Please note that here I want to return a List of the matched items and not bool whether match exists. So please do not close this question or mark similar to the one that returns bool.)

Here is my code

List<string> allCities = new List<string> { "Mumbai", "Redmond", "Cambridge", "London", "Moscow", "New York", "Chicago"};

void SearchList()
{
    string keyword = "mum";
    var citiesSearched = allCities.Where(c => c.Contains(keyword));
    ListView.ItemSource = citiesSearched;
}

I have tried with StringComparer.OrdinalIgnoreCase and StringComparison.OrdinalIgnoreCase but I was getting Error No overload for Contains takes 2 arguments.

This was the modification:

var citiesSearched = allCities.Where(c => c.Contains(keyword, StringComparer.OrdinalIgnoreCase));
// And
var citiesSearched = allCities.Where(c => c.Contains(keyword, StringComparison.OrdinalIgnoreCase));

in both the statements I got the error.

Junaid Pathan
  • 3,850
  • 1
  • 25
  • 47
  • Does this answer your question? [Case insensitive 'Contains(string)'](https://stackoverflow.com/questions/444798/case-insensitive-containsstring) – Thomas Heijtink Nov 23 '19 at 17:51
  • @ThomasHeijtink, No, this question is different. Here I want to get List of items that matches a keyword. Question you suggested targets on `bool` whether keyword exists in the `List`. Both questions target different return types. – Junaid Pathan Nov 23 '19 at 18:25
  • But the idea is exactly the same. But you have a list of strings. The answer I suggested addresses the situation of a single string. What gives? – Thomas Heijtink Nov 24 '19 at 14:58

4 Answers4

1

Just convert to lower case (or upper case) each element of the list before calling Contains and also the keyword. the idea is to have both terms in common case:

var citiesSearched = allCities.Where(c => c.toLower().Contains(keyword.ToLower()));

Try it with:

string keyword = "mum";
List<string> allCities = new List<string> { "Mumbai", "numUmbus","Redmond", "Cambridge", "London", "Moscow", "New York", "Chicago"};
var citiesSearched = allCities.Where(c => c.ToLower().Contains(keyword.ToLower()));
foreach (var s in citiesSearched)
{
    Console.WriteLine(s);
}
Javier Silva Ortíz
  • 2,864
  • 1
  • 12
  • 21
  • There are some cultural quirks that make lower-casing (or upper-casing) a string before a case-sensitive "contains" work differently to just using a culture-sensitive, case-insensitive comparison. I *think* using IndexOf (as per my answer) is a more reliable approach, but I readily admit I don't have a specific example to hand. – Jon Skeet Nov 23 '19 at 17:40
  • @JonSkeet you're totally right, however, the OP didn't mention any of that. Besides, do you think from the post that he/she needs to go into such depths. He/she might have come out with more doubts after reading your approach. – Javier Silva Ortíz Nov 23 '19 at 17:47
  • Would you *expect* the OP to specifically say "I want it to work even in corner cases"? That would be a little odd. And yes, I think in general it's better to post code which works even in corner cases. I don't see why you'd think that my approach would cause more "doubts". It's just using `IndexOf` to find something instead of `Contains`... that's not particularly strange IMO. – Jon Skeet Nov 23 '19 at 18:07
  • @JonSkeet, your code worked in the first go. But however can you explain how? Other answers needed some modifications as I want to get result irrespective of `keyword = "mum"` OR `keyword = "Mum"`. – Junaid Pathan Nov 23 '19 at 18:07
  • 1
    @JunedKhanMomin: Well this answer expects the lower-case version of the city name to contain the keyword, which it won't do if the keyword is "Mum". My approach just uses a case-insensitive search instead. – Jon Skeet Nov 23 '19 at 18:08
  • @JonSkeet I was missing `keyword.ToLower()`, I forgot, thanks to @JunedKhanMomin for mentioning it, it works for "Mum". Sorry if it caused a missunderstanding. – Javier Silva Ortíz Nov 23 '19 at 18:14
  • @JonSkeet ">But however can you explain how?", this is what I was talking about... – Javier Silva Ortíz Nov 23 '19 at 18:18
  • @JavierSilvaOrtíz: I edited my answer slightly to make it clearer - but it's really not terribly complicated. Note the bit about how it actually worked though... – Jon Skeet Nov 23 '19 at 18:44
1

There's no overload of String.Contains that accepts a StringComparison or a StringComparer, but you can use IndexOf with a StringComparison, and use the fact that IndexOf returns -1 if the substring isn't found, or the index of the substring within the larger string otherwise. So you can use:

var citiesSearched = allCities.Where(
    c => c.IndexOf(SearchBar.Text, StringComparison.OrdinalIgnoreCase) != -1);

If you want it to be culture-sensitive for a specific CultureInfo, you can use CultureInfo.CompareInfo to get a CompareInfo, then CompareInfo.IndexOf with CompareOptions.IgnoreCase to perform a culture-sensitive case-insensitive search.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1
List<string> allCities = new List<string> { "Mumbai", "Redmond", "Cambridge", 
"London", "Moscow", "New York", "Chicago"};

void SearchList()
{
    string keyword = "mum";
    var citiesSearched = allCities.Where(c => c.ToLower().Contains(keyword.ToLower()));
    ListView.ItemSource = citiesSearched;
}

transform your text to lower case before the check should do the trick.

pjominet
  • 796
  • 1
  • 8
  • 20
  • See my comments on the answer by Javier Silva Ortíz - I believe this may have problems. I suspect the OP *wants* the ItemSource to be the query rather than a single value - this is the source of items for a list, so it's natural for there to be more than one value. – Jon Skeet Nov 23 '19 at 18:09
1

Simple solution based on one of the fastest string API with StringComparison enum flag:

List<string> allCities = new List<string> { "Mumbai", "Redmond", "Cambridge", "London", "Moscow", "New York", "Chicago"};

void SearchList()
{
    string keyword = "mum";
    var citiesSearched = allCities.Where(c => c.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);
    ListView.ItemSource = new List(citiesSearched);
}
Jacek Blaszczynski
  • 3,183
  • 14
  • 25