I want to search a list of strings using a set of characters and want to find matches regardless of order. For example if my list contains
List<string> testList = new List<string>() { "can", "rock", "bird" };
I want to be able to search using "irb" and have it return bird. I have to do this many times so I am looking for the most efficient way of doing it.
var query = "irb";
List<string> testList = new List<string>() { "can", "rock", "bird" };
var result = testList.Where(i => query.All(q => i.Contains(q)));
For each item in the testList test to see if it contains all the letters in query
For your scenario, you need to check each character of word in another list of word.
For that, you can do like this :
// Checks whether all character in word is present in another word
Func<string, string, bool> isContain = (s1, s2) =>
{
int matchingLength = 0;
foreach (var c2 in s2.ToCharArray())
{
foreach (var c1 in s1.ToCharArray())
{
if (c1 == c2)
++matchingLength;
}
}
// if matched length is equal to word length given, it would be assumed as matched
return s2.Length == matchingLength;
};
List<string> testList = new List<string>() { "can", "rock", "bird" };
string name = "irb";
var fileredList = testList.Where(x => isContain(x, name));
If you don't care about matching duplicates than checking if all characters in a sequence you are searching for are contained in the word would do for predicate:
"irb".Except("bird").Count() == 0
And whole condition:
List<string> testList = new List<string>() { "can", "rock", "bird" };
var search = "irb";
var matches = testList.Where(word => !search.Except(word).Any());
Notes:
you need to normalize all words to lowercase if you need mixed case letters to match.
if performance of searching for different values is critical - convert search string to HashSet first and do except manually.
if you need to match different values against same list many times - convert list of strings to list of HashSet and use search.All(c => wordAsHashSet.Contains(c)) as condition.
You can use linq to achieve this
List<string> testList = new List<string>() { "can", "rock", "bird" };
var lst = testList.Where(x => x.ToUpperInvariant().Contains("IRD")).ToList();
Make sure you also compare the cases using ToUpper and the string you want to compare also make it UpperCase
Related
I have a list with several ingredients:
List<string> vegList = new List<string>();
where there are several strings like: "cherry", "butter", "bread".
My idea was to have a dictionary or something like that having a recipe string, the name of that recipe is returned if it had one or more elements from the list.
I tried to make a dictionary, and array too, but I didn't get what I wanted.
can anyone help?
i tried this but i don't know what to do anymore
myString = "receit pineapple cake, cherry, bread ..."
foreach(string item in vegList )
{
if(item.Contains(myString))
return item;
}
Try Linq Any:
List<string> vegList = new List<string>()
{ "cherry", "butter", "bread"};
string recipe = "butterbread";
bool showRecipe = vegList.Any(s => recipe.Contains(s));
ShowRecipe returns true.
Edit 1:
The following code searches for recipes in recipes list and returns a matchedRecipes list with recipes that match the the words from vegList.
List<string> vegList = new List<string>()
{ "cherry", "butter", "bread"};
List<string> recipes = new List<string>()
{ "steak", "butterbread", "cherrycake"};
List<string> matchedRecipes = recipes.Where(x => vegList.Any(s => x.Contains(s))).ToList();
matchedRecipes list contains "butterbread" and "cherrycake"
Edit 2: It would also be helpful to ignore case of letters.
List<string> vegList = new List<string>()
{ "cherry", "butter", "bread"};
List<string> recipes = new List<string>()
{ "steak", "Butterbread", "Cherrycake"};
List<string> matchedRecipes = recipes.Where(x => vegList
.Any(s => x.ToLower().Contains(s.ToLower())))
.ToList();
If each recipe has a vegList, or more specifically, you have a Recipe class with a List<string> vegList field, and let's say you have a List<Recipe> recipes somewhere:
var ingredient = "cherry";
var matches = recipes.FindAll(r => r.vegList.contains(ingredient));
matches will be a List<Recipe> with recipes containing "cherry" as an ingredient.
With the new scenario as the question was updated, first make sure your string has ingredients separated all by a space (let's not make it harder).
myIngredients = myString.split(" ");
Then to find the recipes:
var matches = recipes.FindAll(r => r.vegList.Any(l => myIngredients.contains(l)));
In this case a recipe is selected if its vegList contains at least one of the ingredients in myIngredients.
I have a list say
List<string> someList = new List{"1-30","20-10","21-23","34-80"};
I need to split the list so I have with following values
{"1","20","21","34"};
I tried
someList
.SelectMany(n => n.Split('-')[0])
.ToList();
But it is not giving me the desired result.
UPDATE:
Sorry everyone, Using Select solved my issue. One of those days, when you make silly mistakes
You have to take the 1st part of each item and you can do with a help of Substring (i.e. take item's value up to -):
List<string> someList = new List{
"1-30", "20-100", "21-23", "34-80"};
var result = someList
.Select(item => item.Substring(0, item.IndexOf('-')))
.ToList(); // if you want a new list
In case you want to change the existing list, just implement a loop:
for (int i = 0; i < someList.Count; ++i)
someList[i] = someList[i].Substring(0, someList[i].IndexOf('-'));
Edit: what's going on when you put SelectMany instead of Select.
SelectMany wants IEnumerable<T> as an outcome and since String is IEnumerable<char> you have a flatten List<char>s:
['1', '2', '0', '2', '1', '3', '4']
Please, notice that each string ("1", "20", "21", "34") is treated as being a collection of chars (['1']; ['2', '0']; ['2', '1']; ['3', '4'])
You don't need to use selectMany since you don't need to flatten your list. Using Select will return each string in the list
{"1-30", "20-100"...etc}
. Using SelectMany will actually flatten the strings into a sequence of chars resulting in
{"1", "-", "3", "0" ...etc}
So your split will result in the wrong result.
.
You just select each item in your list, split the item on the '-' char and select the first result from the split. This should give you the correct result.
List<string> someList = new List<string> { "1-30", "20-100", "21-23", "34-80" };
var splitString = someList.Select(x => x.Split('-').First()).ToList();
Not as pretty as you probably want, but it does the work.
List<string> someList = new List<string>{"1-30","20-100","21-23","34-80"};
List<string> newList = new List<string>();
foreach (var v in someList)
{
string[] s = v.Split('-');
newList.Add(s[0]);
}
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
}
Hello guys this is what I have so far.
public List<Word> GetWords(string[] words)
{
return DbContext.Words.Where(w => words.Contains(w.Value.ToLower());
}
The problem is that when I pass for example List containing two same words I am getting one entity. What can be an effective way of getting entity for each word even if it's duplicate?
Given this simplified test case, where sourceData represents your DbContext.Words:
var sourceData = new string[]
{
"a",
"b",
"c"
};
var wordsToFind = new string[]
{
"a",
"a"
};
A silly way would be to execute the query for each requested input:
var foundWords = wordsToFind.Select(w =>
sourceData.Where(s => s.Contains(w.ToLower()))).ToList();
Or you could execute the query once, then duplicate the results per input by executing the query in-memory again:
var foundWords = sourceData.Where(w =>
wordsToFind.Contains(w.ToLower())).ToList();
var result = wordsToFind.SelectMany(w =>
foundWords.Where(f =>
f.Contains(w.ToLower()))).ToList();
Not sure if you want substring or equal words, following query returns multiple records but checking for the same word not substring.
public List<Word> GetWords(string[] words)
{
var results = from word in DbContext.Words.ToArray()
join str in words on word.ToLower() equals str
select word;
return results.ToList();
}
EDIT: First get the filtered records from the database and then join it with the array again to get multiple records. Same thing checking twice. Stored procedure would be more efficient for a huge collection.
public List<Word> GetWords(string[] words)
{
var results = from word in DbContext.Words
.Where(w => words.Contains(w.Value.ToLower())
.ToArray()
join str in words on str.Contains(word.ToLower())
equals true
select word;
return results.ToList();
}
I have a string containing up to 9 unique numbers from 1 to 9 (myString) e.g. "12345"
I have a list of strings {"1"}, {"4"} (myList) .. and so on.
I would like to know how many instances in the string (myString) are contained within the list (myList), in the above example this would return 2.
so something like
count = myList.Count(myList.Contains(myString));
I could change myString to a list if required.
Thanks very much
Joe
I would try the following:
count = mylist.Count(s => myString.Contains(s));
It is not perfectly clear what you need, but these are some options that could help:
myList.Where(s => s == myString).Count()
or
myList.Where(s => s.Contains(myString)).Count()
the first would return the number of strings in the list that are the same as yours, the second would return the number of strings that contain yours. If neither works, please make your question more clear.
If myList is just List<string>, then this should work:
int count = myList.Count(x => myString.Contains(x));
If myList is List<List<string>>:
int count = myList.SelectMany(x => x).Count(s => myString.Contains(s));
Try
count = myList.Count(s => s==myString);
This is one approach, but it's limited to 1 character matches. For your described scenario of numbers from 1-9 this works fine. Notice the s[0] usage which refers to the list items as a character. For example, if you had "12" in your list, it wouldn't work correctly.
string input = "123456123";
var list = new List<string> { "1", "4" };
var query = list.Select(s => new
{
Value = s,
Count = input.Count(c => c == s[0])
});
foreach (var item in query)
{
Console.WriteLine("{0} occurred {1} time(s)", item.Value, item.Count);
}
For multiple character matches, which would correctly count the occurrences of "12", the Regex class comes in handy:
var query = list.Select(s => new
{
Value = s,
Count = Regex.Matches(input, s).Count
});
try
var count = myList.Count(x => myString.ToCharArray().Contains(x[0]));
this will only work if the item in myList is a single digit
Edit: as you probably noticed this will convert myString to a char array multiple times so it would be better to have
var myStringArray = myString.ToCharArray();
var count = myList.Count(x => myStringArray.Contains(x[0]));