Intersect 2 list if first list contains part of another - c#

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();

Related

How to add add items near to next list

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();

How to modify each element of a list into a new list?

I would like to learn how to do the following code using a => or ForEach or something else. It basically gets all elements of List1, modifies it, and then stores it into a new List2. List1 is not altered.
//List1 exists from before
List<string> List2 = new List<string>();
foreach (element in List1)
{
List2.Add(element + " concact string");
}
Is there an easy way to write this code in a more concise/readable way?
Using the System.Linq extension method Select, it's simple to select each item from List1, modify it, and return the results as a new List<string>:
List<string> List2 = List1.Select(element => element + " concat string").ToList();
var newList = List1.Select(x => x.Concat(" concact string")).ToList();

How to do "nothing" in the else part of ternary operator

I want to filter values of a list based on whether or not they are contained in some other list. If an element is in the list I will select it, else I want to skip it or basically do nothing.
Below is what I tried to do. How can I achieve this?
List<string> sheetNames = new List<string>() {"1","10"};
List<string> projects= new List<string>() {"1","2","3","4","5","6","7"};
IEnumerable<string> result =
sheetNames.Select(x => projects.Contains(x)
? x
: /*Want to do nothing here */);
You can use Enumerable.Intersect method to get the common values from the two lists.
IEnumerable<string> commonValues = projects.Intersect(sheetNames);
List<string> sheetNames = new List<string>() {"1","10"};
List<string> projects= new List<string>() {"1","2","3","4","5","6","7"};
IEnumerable<string> result = sheetNames.Where(x => projects.Contains(x));

Comparing strings in 2 list using Linq

I need to compare to list with strings, and find whitch elements that are similar. ie.
List<string> listA = {"ProfileHeight", "ProfileWidth", "WebThickness"}
List<string> listB ={"ProfileHeightVisibility", "ProfileWidthVisibility", "WebThicknessVisibility", "FlangeThicknessVisibility", "DepthVisibility"}
I was wondering if it is possible to use Linq. I want the result to be a list with the elements from ListB that have a name similar to the strings in listA. Where the statemant i.e. "ProfileHeightVisibility.Contains("ProfileHeight") = true
You mean you want items in listB where it contains any of the elements in listA?
listB.Where(b => listA.Any(a => b.Contains(a))
You can do it in LINQ:
listB.Where(e => listA.Any(a => e.Contains(a)));
Bear in mind that this algorithm has a runtime cost similar to O(n^2), it will therefore slow down quickly as the number of elements in your lists grows.
You can also implement things like that :
public class EqualityComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return y.Contains(x);
}
public int GetHashCode(string obj)
{
return 1;
}
}
and then use intersect like that:
listB.Intersect(listA, new EqualityComparer()).ToList();
Yes you can do such thing with LINQ
public List<string> GetSimilarStrings(List<string> list1, List<string> list2)
{
return (from item in list1 from item2 in list2 where string.Equals(item,item2,StringComparison.InvariantCultureIgnoreCase) select item).ToList();
}
List<string> listA = new List<string> { "zinmin", "zin1", "zin2" };
List<string> listB = new List<string> { "zinmin", "min1", "min2" };
List<string> matching = listA.Intersect(listB).ToList();
matching result will come {"zinmin"} . Sorting order doesn't matter.

Find duplicates in a collection of lists

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();
}

Categories