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.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
Is it possible to join 2 lists and create one to many relationship?
For example,
list 1:
{"High", "Med", "Low"}
list 2:
{"Submitted", "In Progress", "Draft", "Rejected"}
final list, I will have values like this:
{
{"High", "Submitted"}, {"High", "In Progress"},{"High", "Draft"}, {"High", "Rejected"},
{"Med", "Submitted"}, {"Med", "In Progress"},{"Med", "Draft"}, {"Med", "Rejected"},
{"Low", "Submitted"}, {"Low", "In Progress"},{"Low", "Draft"}, {"Low", "Rejected"}
}
Not sure if this is what you are looking for, but you can use Select and SelectMany to create the final List of KeyVaulePair.
var list1 = new List<string>() { "High", "Medium", "Low" };
var list2 = new List<string>() { "Submitted", "In-Progress", "Draft", "Rejected" };
var joined = list1.SelectMany(val1 => list2.Select(val2 => new KeyValuePair<string, string>(val1, val2)));
foreach(var res in joined)
{
Console.WriteLine(res.Key + "," + res.Value);
}
If you want to use imperative style of coding, then just create 2 for loops
It seems, that you are looking for a Cartesian Join, you can do it with a help of Linq:
var list1 = new List<string>() {
"High", "Medium", "Low" };
var list2 = new List<string>() {
"Submitted", "In-Progress", "Draft", "Rejected" };
// I've combined values as named tuple: (string first, string second)
// but you can use anonymous class, or just concat string strings
var joined = list1
.SelectMany(item1 => list2.Select(item2 => (first: item1, second: item2)));
.ToList();
Let's have a look:
Console.Write(string.Join(Environment.NewLine, joined));
Outcome:
(High, Submitted)
(High, In-Progress)
(High, Draft)
(High, Rejected)
(Medium, Submitted)
(Medium, In-Progress)
(Medium, Draft)
(Medium, Rejected)
(Low, Submitted)
(Low, In-Progress)
(Low, Draft)
(Low, Rejected)
LINQ method syntax for joins is pretty ugly and even counterintuitive, IMHO; query syntax looks much nicer/easier to read:
from s in list1
from t in list2
select new { s, t }
Or as a tuple:
from s in list1
from t in list2
select ( s, t )
If you want to do Cartesian product and want to store it in text-value pair then you can use List with SelectListItem. It will give you list with text-value pair.
var list1 = new List<string>() { "High", "Medium", "Low" };
var list2 = new List<string>() { "Submitted", "In-Progress", "Draft", "Rejected" };
List<SelectListItem> list3 = new List<SelectListItem>();
foreach (string str in list1)
{
foreach(string str2 in list2)
{
list3.Add(new SelectListItem()
{ Text = str, Value = str2 });
}
}
You can use the join method from LINQ:
List<(string,string)> joined = list1.Join(list2, x => true, y => true, (x,y) => (x,y)).ToList();
The second and third parameter are selectors for list1 and list2. If both are the same, a joined value will be created. If we give the same constant value for both selectors, the joining condition is always fulfilled and hence all possible pairs are created.
Online demo: https://dotnetfiddle.net/JaK6ff
I'm trying to make a program like wordlist generator.
I want to add the items on the 2nd list next to each item on the 1st list.
`
List<string> list1 = new List<string>() {"tomato", "ball", "icecream", "blue"};
List<string> list2 = new List<string>() { "123", "yellow", "green" };
`
//Values to be added to Listing 3: tomato123, tomatoyellow, tomatogreen, ball123, ballyellow, ballgreen bla bla bla
To solve your problem, we will iterate over one of the lists, and for every item in it, we will create all the possible combinations with words from the other list. With LINQ, it would look something like this:
var list3 = list1.Select(w1 => list2.Select(w2 => w1 + w2)).ToList();
The problem is that now list3 is of type List<IEnumerable<string>> because we have a list of combinations for every word in list1. To flatten the result, all we need is to change the Select projection to a SelectMany flattened projection:
var list3 = list1.SelectMany(w1 => list2.Select(w2 => w1 + w2)).ToList();
Based on your requirement it might be useful. Please have a look.
static void AddLists()
{
List<string> list1 = new List<string>() { "tomato", "ball", "icecream", "blue" };
List<string> list2 = new List<string>() { "123", "yellow", "green" };
var resultList = from l1 in list1
from l2 in list2
select string.Concat(l1, l2);
}
My advice would be to create an extension method, instead of a LINQ statement that is difficult to understand: readers will immediately see what it does, it is easier to test and easier to change.
See extension methods demystified
public static IEnumerable<string> ConcatCombinations(
this.IEnumerable<string> sequenceA,
IEnumerable<string> sequenceB)
{
// TODO: invent a proper name
foreach (string textA in sequenceA)
foreach (string textB in sequenceB)
yield return textA + textB;
}
This code is way simpler than any solution using LINQ methods. Anyone will immediately see what it does.
Usage:
List<string> list1 = ...
string[] array1 = ...
List<string> concatenated = list1.ConcatCombinations(array1).ToList();
If you want to make a more generic method, consider this:
public static IEnumerable<TResult> MakeCombinations<TA, TB, TResult>(
this IEnumerable<TA> itemsA,
IEnumerable<TB> itemsB,
Func<TA, TB, TResult> resultSelector)
{
foreach (TA itemA in itemsA)
foreach (TB itemB in itemsB)
{
TResult result = resultSelector(itemA, itemB);
yield return result;
}
}
Usage:
List<string> list1 = ...
List<string> list2 = ...
List<string> concatenated = list1.ConcatCombinations(list2,
// parameter ResultSelector: concat every a and b:
(a, b) => a+b)
.ToList();
Or just change your ConcatCombinations:
public static IEnumerable<string> ConcatCombinations(
this.IEnumerable<string> sequenceA,
IEnumerable<string> sequenceB)
{
return sequenceA.MakeCombinations(sequenceB,
(a, b) => a + b);
}
Another completely different example, that shows you the reusability of the code:
var maleBallroomDancers = ...
var femaleBallroomDancers = ...
var danceCombinations = maleBallroomDancers.MakeCombinations(femaleBallroomDancers,
(male, female) => new
{
Male = male,
Female = female,
})
.ToList();
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
I have 2 list of string, list A and list B. list A is a list of strings containing paths, and the other contains strings of folder. Examples:
List<string> listA = new List<string>{ "c:\myPath\FolderA\blabla\", "c:\myPath\FolderB\blabla2\", "c:\myPath\FolderA\blabla3\" "c:\myPath\FolderC\blabla\"};
List<string> listB = new List<string> { "FolderA, FolderC"};
I want to have a method that compares the 2 list. If listA contains any of listB it is valid, else I don't want it. So based on this logic I'd have:
List<string> listReturn = new List<string>{ "c:\myPath\FolderA\blabla\", "c:\myPath\FolderA\blabla3\" "c:\myPath\FolderC\blabla\"};
So far all I've done is a method that iterates through the first list and does a Contain call on the string with a Linq Any call, like this:
private static List<string> FilterList(List<string> listA, List<string> listB)
{
List<string> listReturn = new List<string>();
foreach (string val in listA)
{
if (listB.Any(item => val.Contains(item)))
{
listReturn.Add(val);
}
}
return listReturn;
}
It's not bad, but I want to use a Linq approach or a .NET approach if there's an Intersect method available for this. Thank you.
Use Where() against the listA to filter items in this list and Exists() on listB for the filter condition:
List<string> listA = new List<string> {#"c:\myPath\FolderA\blabla\", #"c:\myPath\FolderA\blabla2\", #"c:\myPath\Folder\blabla3\", #"c:\myPath\FolderC\blabla\"};
List<string> listB = new List<string> { "FolderA", "FolderC" };
var intersect = listA.Where(a => listB.Exists(b => a.Contains(b)));
Try this
var result = listA.Where(i => listB.Any(y => i.Contains(y)).ToList();
If I have a dictionary containing 2 or more lists, how can I quickly find shared items between these lists and add these shared items to a list external to the dictionary?
For example:
list1:
eng;English
lir;Liberian English
list2:
eng;English
bav;Vengo
list3:
lat;Latin
extList:
eng;English
This shared item is then removed from the lists inside the dictionary.
I have added list3 to show that a superfluous item may be ignored, and that I have specified 2 or more lists.
As I understand you have two lists and need to find intersection between those lists and add this intersection to the third list:
var list1 = new[] { "eng;English", "lir;Liberian", "English" };
var list2 = new[] { "eng;English", "bav;Vengo", "English" };
extList.AddRange(list1.Intersect(list2));
Suppose we have a list of lists (or a dictionary, which would add a Key):
List<List<string>> lists = new List<List<string>>()
{
new List<string> {"Hello", "World", "7"},
new List<string> {"Hello", "7", "Person"},
new List<string> {"7", "7", "Hello"}
};
You can find items that are present in all lists:
List<string> extList = lists.Cast<IEnumerable<string>>()
.Aggregate((a, b) => a.Intersect(b)).ToList();
If you want to get strings that are common to just a few lists, you can use:
var counts = from str in lists.SelectMany(list => list)
group str by str into g
where g.Count() > 1
select new { Value = g.Key, Count = g.Count() };
You can drop the last line if you don't care how many times each word appears. Note that this will not tell you in which list the word is.
Here's a function that will take a dictionary, remove any string that is in more than one list in the dictionary, and return the list of strings it removed:
static List<string> FindAndRemoveDuplicates(Dictionary<string, List<string>> data)
{
// find duplicates
var dupes = new HashSet<string>(
from list1 in data.Values
from list2 in data.Values
where list1 != list2
from item in list1.Intersect(list2)
select item);
// remove dupes from lists in the dictionary
foreach (var list in data.Values)
list.RemoveAll(str => dupes.Contains(str));
// return a list of the duplicates
return dupes.ToList();
}